Generate and run PowerShell scripts dynamically

In my prior post Use new XML Features of VB to generate dynamic scripts and text files , we generated a simple batch file. It’s difficult to modify the registry or manipulate a COM object

PowerShell scripts allow you to manipulate files, registry and COM objects, using a uniform object manipulation metaphor. For example, you can use CD and DIR at a command prompt to navigate the file system, the registry and certificate store too.

Here's a simple sample navigating the registry of Fox: (user typed text in this color)

Windows PowerShell

Copyright (C) 2006 Microsoft Corporation. All rights reserved.

PS C:\Documents and Settings\calvinh> cd hkcu:

PS HKCU:\> cd Software

PS HKCU:\Software> cd HKCU:\Software\Microsoft\VisualFoxPro

PS HKCU:\Software\Microsoft\VisualFoxPro> dir

   Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\VisualFoxPro

SKC VC Name Property

--- -- ---- --------

  5 0 9.0 {}

PS HKCU:\Software\Microsoft\VisualFoxPro> cd 9.0

PS HKCU:\Software\Microsoft\VisualFoxPro\9.0> dir

   Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\VisualFoxPro\9.0

SKC VC Name Property

--- -- ---- --------

  0 1 ChooseColor {(default)}

  0 8 Coverage {FrmzoomHeight, FrmzoomTop, FrmzoomWidth, FrmzoomLeft...}

  0 7 Desktop {Zoomed, Row, Column, Height...}

  0 0 Fonts {}

  4 192 Options {LastProject, TALK, StatusBar, NOTIFY...}

PS HKCU:\Software\Microsoft\VisualFoxPro\9.0>

This PowerShell script sample modifies the setting of SET SAFETY by directly manipulating the registry, then forcing VFP to reread the registry settings using SYS(3056)

ERASE d:\t.txt

*https://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx

*Set-ExecutionPolicy remotesigned

SET SAFETY OFF

?"Safety before",SET("Safety")

TEXT TO myvar

#This is a sample powershell script

#get-process > d:\t.txt

#get-psdrive > d:\t.txt

#CD HKCU:\Software\Microsoft\VisualFoxPro\9.0

#get-Item * >> d:\t.txt

#can specify path to registry

#get setting of all reg keys starting with "s":

#get-ItemProperty -path registry::HKCU\Software\Microsoft\VisualFoxPro\9.0\Options s* >> d:\t.txt

#get-ItemProperty -path registry::HKCU\Software\Microsoft\VisualFoxPro\9.0\Options safety >> d:\t.txt

set-ItemProperty -path registry::HKCU\Software\Microsoft\VisualFoxPro\9.0\Options safety ON >> d:\t.txt

ENDTEXT

STRTOFILE(myvar,"d:\Myscript.ps1")

! powershell d:\Myscript

?STRCONV(SUBSTR(FILETOSTR("d:\t.txt"),3),6) && convert from Unicode, remove ByteOrderMark

SYS(3056) && Force VFP to reread registry

?"Safety After: ",SET("safety")

SET SAFETY OFF && restore value

You can even create a VFP COM Object from within a PowerShell script and invoke its methods: (using my favorite VFP COM Object "t1.c1")

Here's a PowerShell script sample that creates an instance of Excel, and passes it to the VFP COM object for further manipulation: The hardest part of this code was trying to figure out how to close Excel without saving changes!

PowerShell variables start with “$”, comments start with “#”

SET SAFETY OFF

sOutputFile="d:\t.txt"

ERASE (sOutputFile)

ERASE (sOutputFile)

TEXT TO myvar TEXTMERGE

#create Excel

$oExcel = New-Object -ComObject Excel.Application

#create VFP COM Object

$oVFP = New-Object -ComObject t1.c1

#Pass Excel to VFP object

$oVFP.MyDoCmd("p2.Visible=1",$oExcel,0,0,0)

#Get the name of the object

$oVFP.MyEval("p2.name",$oExcel,0,0,0) >> <<sOutputFile>>

#Add a workbook

$oVFP.MyDoCmd("p2.Workbooks.Add",$oExcel,0,0,0)

$pv="PowerShell variable"

#Change the 1st cell's value to a combination of VFP and Powershell vars

$oVFP.MyDoCmd("p2.Cells(1,1).value='Hi from VFP '+p3",$oExcel,$pv,0,0)

$oVFP.MyDoCmd("DECLARE integer MessageBoxA IN WIN32API integer,string,string,integer",0,0,0,0)

$oVFP.MyEval("MessageBoxA(0,'Hi From VFP inside PowerShell','',0)",0,0,0,0)

#Close Excel workbook without saving!

$oVFP.MyDoCmd("p2.ActiveWorkbook.Close(.f.)",$oExcel,0,0,0)

$oVFP.MyDoCmd("p2.Visible=0",$oExcel,0,0,0)

$oVFP.MyDoCmd("p2.Quit",$oExcel,0,0,0)

ENDTEXT

STRTOFILE(myvar,"d:\Myscript.ps1")

! powershell d:\Myscript

IF FILE(sOutputFile)

      ?STRCONV(SUBSTR(FILETOSTR(sOutputFile),3),6) && convert from Unicode, remove ByteOrderMark

ENDIF

You can do this from VB using the new XML features (Use new XML Features of VB to generate dynamic scripts and text files )

Module Module1

    Sub Main()

        Dim sOutputFile = "d:\t.txt"

        Dim sScriptFile = "d:\t.ps1"

        If My.Computer.FileSystem.FileExists(sOutputFile) Then

            My.Computer.FileSystem.DeleteFile(sOutputFile)

  End If

        Dim PowerShellScriptXML = <myxml>

#create Excel

$oExcel = New-Object -ComObject Excel.Application

#create VFP COM Object

$oVFP = New-Object -ComObject t1.c1

#Pass Excel to VFP object

$oVFP.MyDoCmd("p2.Visible=1",$oExcel,0,0,0)

#Get the name of the object

$oVFP.MyEval("p2.name",$oExcel,0,0,0) >> <%= sOutputFile %>

#Add a workbook

$oVFP.MyDoCmd("p2.Workbooks.Add",$oExcel,0,0,0)

$pv="PowerShell variable"

#Change the 1st cell's value to a combination of VFP and Powershell vars

$oVFP.MyDoCmd("p2.Cells(1,1).value='Hi from VFP '+p3",$oExcel,$pv,0,0)

$oVFP.MyDoCmd("DECLARE integer MessageBoxA IN WIN32API integer,string,string,integer",0,0,0,0)

$oVFP.MyEval("MessageBoxA(0,'Hi From VFP inside PowerShell','',0)",0,0,0,0)

#Close Excel workbook without saving!

$oVFP.MyDoCmd("p2.ActiveWorkbook.Close(.f.)",$oExcel,0,0,0)

$oVFP.MyDoCmd("p2.Visible=0",$oExcel,0,0,0)

$oVFP.MyDoCmd("p2.Quit",$oExcel,0,0,0)

                 </myxml>

        Console.WriteLine(PowerShellScriptXML.Value)

        My.Computer.FileSystem.WriteAllText(sScriptFile, PowerShellScriptXML.Value, False, Text.Encoding.ASCII)

        Dim proc = System.Diagnostics.Process.Start("PowerShell", sScriptFile)

        proc.WaitForExit()

        Dim ss = My.Computer.FileSystem.ReadAllText(sOutputFile)

        MsgBox("Proc Done " + ss)

    End Sub

End Module

End of code

See also

How to create the general purpose "T1.c1" server: Blogs get 300 hits per hour: Visual FoxPro can count.