Oooey-GUI Script Searcher

October 6th, 2011 Mark A. Weaver Comments off
Rating 3.50 out of 5

As a follow up to my Script Tagging post, I have put together a Powershell GUI script that one can use to search a folder structure that has tagged scripts in it.

I haven’t documented this as well as I normally would, so perhaps that will come at a later time.

Basically you launch it and the “Folder Root” will default to the current directory.

Once you enter some values in the text boxes, and “Execute” the search, the script will recursively interrogate all powershell scripts in the root folder and all child folders looking for the appropriate tags as created by the “Tagging” post.

UI ScreenShot

I hope you find it helpful and here is the code!
As always… Happy scripting!!!
— Mark

function Find-Script
{
param($Term="/*" ,$Path = ".\",$FilePattern = "*.ps1",$Tag="/*", $Auth="/*", $Desc="/*", $Misc="/*")
 
$AllScripts = Get-ChildItem * -Path $Path -include $FilePattern -recurse
[array]$AllTags = $Null
[array]$FoundScripts=$null
Foreach ($Script in $AllScripts)
{
  $Contents = Get-Content $Script
  [array]$AllTags = $Null
  if ($Contents -imatch "_BEGINMARKUP")
   {
    # ($Contents -imatch "_TAG:").gettype()
	$Found = $False
     $Tags = ([string]($Contents -match "_TAG:")).replace("#","").trim().split(":")[1].trim()
	 $Author= ([string]($Contents -match "_AUTH:")).replace("#","").trim().split(":")[1].trim()
     $Description = ([string]($Contents -match "_DESC:")).replace("#","").trim().split(":")[1].trim()
	 $Version = ([string]($Contents -match "_VER:")).replace("#","").trim().split(":")[1].trim()
	 $Miscellaneous = ([string]($Contents -match "_MISC:")).replace("#","").trim().split(":")[1].trim()
	 $ModifiedDate =([string]($Contents -match "_DATE:")).replace("#","").trim().split(":")[1].trim()
	 $AllTags +=$Tags
	 $AllTags +=$Author
	 $AllTags +=$Description
	 $AllTags +=$Version
	 $AllTags +=$Miscellaneous
 
	if (($Tags -imatch $Tag) -and ($Author -imatch $Auth) -and ($Description -imatch $Desc) -and ($Miscellaneous -imatch $Misc)-and ($AllTags -imatch $Term)){$Found = $True}
 
	If ($Found -eq $true)
	{
	  $FoundItem = "" | Select-Object Script,Author,LastModified,Tags,Description
	  $FoundItem.Script = $Script
	  $FoundITem.Author = $Author
	  $FoundItem.LastModified = $Script.LastWriteTime
	  $FoundItem.Tags = $Tags
	  $FoundItem.Description = $Description
	  $FoundScripts += $FoundItem
	}
   }
}
If ($FoundScripts -ne $null){
 # Write-Host "Search Term: $Term"
 return $FoundScripts
  }
  else
  {
    Write-Host "No Scripts found with specified criteria." -ForegroundColor Yellow
  }
}
#Generated Form Function
function GenerateForm {
 
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion
 
#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$btnBrowse = New-Object System.Windows.Forms.Button
$txtPath = New-Object System.Windows.Forms.TextBox
$button1 = New-Object System.Windows.Forms.Button
$label5 = New-Object System.Windows.Forms.Label
$label4 = New-Object System.Windows.Forms.Label
$label3 = New-Object System.Windows.Forms.Label
$label2 = New-Object System.Windows.Forms.Label
$label1 = New-Object System.Windows.Forms.Label
$label6 = New-Object System.Windows.Forms.Label
$txtTag = New-Object System.Windows.Forms.TextBox
$txtMisc = New-Object System.Windows.Forms.TextBox
$txtAuth = New-Object System.Windows.Forms.TextBox
$fldBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
$txtDesc = New-Object System.Windows.Forms.TextBox
$textBox2 = New-Object System.Windows.Forms.TextBox
$txtTerm = New-Object System.Windows.Forms.TextBox
$dataGridView1 = New-Object System.Windows.Forms.DataGridView
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects
 
#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$button1_OnClick=
{
#TODO: Place custom script here
 
if ($txtPath.text -eq "") {
$fldBrowser.ShowDialog()
$txtPath.Text = $fldBrowser.SelectedPath
}
if ($txtAuth.Text -eq ""){$Auth = "/*"}else{$Auth = $txtAuth.Text.trim()}
if ($txtTag.Text -eq ""){$Tags = "/*"}else{$Tags = $txtTag.Text.trim()}
if ($txtMisc.Text -eq ""){$Misc = "/*"}else{$Misc = $txtMisc.Text.trim()}
if ($txtTerm.Text -eq ""){$Term = "/*"}else{$Term = $txtTerm.Text.trim()}
if ($txtDesc.Text -eq ""){$Desc = "/*"}else{$Desc = $txtDesc.Text.trim()}
 
#Write-Host ($txtAuth.Text -eq "")
$Path = $txtPath.Text
#Write-Host "find-script -Path ""$Path"" -Auth $Auth -Desc $Desc -Misc $Misc -Tag $Tags -Term $Term"
 
$FoundScripts = find-script -Path "$Path" -Auth "$Auth" -Desc "$Desc" -Misc "$Misc" -Tag "$Tags" -Term "$Term"
$array= new-object System.Collections.ArrayList
if ($FoundScripts.count -gt 1) {
$array.addrange($FoundScripts)}
else
{
$array.add($FoundScripts)
}
    $dataGridview1.datasource = $array
    $form1.refresh() 
 
}
 
$dataGridView1_Selectionchanged =
{
   $f = ""
   $SelectedPath = $datagridview1.selectedcells[0].value
   if ($SelectedPath -ne $null)
   {
   $f = Get-Content $SelectedPath
   }
   $textBox2.lines =$f
}
$btnBrowse_OnClick=
{
$object = New-Object -comObject Shell.Application  
 
    $folder = $object.BrowseForFolder(0, $message, 0, "")
    if ($folder -ne $null) { 
 
$txtPath.Text = $folder.self.Path
}
}
 
$handler_form1_Load=
{
#TODO: Place custom script here
 
}
 
$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}
 
#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 650
$System_Drawing_Size.Width = 1050
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Name = "form1"
$form1.Text = "Script Search Interface"
$form1.add_Load($handler_form1_Load)
 
$button1.DataBindings.DefaultDataSourceUpdateMode = 0
 
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 900
$System_Drawing_Point.Y = 35
$button1.Location = $System_Drawing_Point
$button1.Name = "button1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 100
$button1.Size = $System_Drawing_Size
$button1.TabIndex = 2
$button1.Text = "Execute Search"
$button1.UseVisualStyleBackColor = $True
$button1.add_Click($button1_OnClick)
 
$form1.Controls.Add($button1)
 
$btnBrowse.DataBindings.DefaultDataSourceUpdateMode = 0
 
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 259
$System_Drawing_Point.Y = 36
$btnBrowse.Location = $System_Drawing_Point
$btnBrowse.Name = "btnBrowse"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 60
$btnBrowse.Size = $System_Drawing_Size
$btnBrowse.TabIndex = 14
$btnBrowse.Text = "Browse..."
$btnBrowse.UseVisualStyleBackColor = $True
$btnBrowse.add_Click($btnBrowse_OnClick)
 
$form1.Controls.Add($btnBrowse)
$txtPath.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 38
$txtPath.Location = $System_Drawing_Point
$txtPath.Name = "txtPath"
$txtPath.Text = (Get-Location).Path
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 241
$txtPath.Size = $System_Drawing_Size
$txtPath.TabIndex = 13
 
$form1.Controls.Add($txtPath)
 
$fldBrowser.RootFolder = [System.Environment+SpecialFolder]::Personal
 
$dataGridView1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 80
$dataGridView1.Location = $System_Drawing_Point
$dataGridView1.Name = "dataGridView1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 218
$System_Drawing_Size.Width = 1000
$dataGridView1.Size = $System_Drawing_Size
$dataGridView1.TabIndex = 0
$dataGridView1.Autosizecolumnsmode="AllCells"
$dataGridView1.SelectionMode = 1
$dataGridView1.Readonly = $True
$dataGridView1.add_SelectionChanged($dataGridView1_Selectionchanged)
$form1.Controls.Add($dataGridView1)
 
$textBox2.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 300
$textBox2.Location = $System_Drawing_Point
$textBox2.Multiline = $True
$textBox2.Name = "textBox2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 350
$System_Drawing_Size.Width = 1000
$textBox2.Size = $System_Drawing_Size
$textBox2.TabIndex = 3
$textbox2.scrollbars = 3
$textBox2.Readonly=$true
$textBox2.wordwrap = $False
 
$form1.Controls.Add($textBox2)
$label5.DataBindings.DefaultDataSourceUpdateMode = 0
 
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 703
$System_Drawing_Point.Y = 38
$label5.Location = $System_Drawing_Point
$label5.Name = "label5"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 17
$System_Drawing_Size.Width = 46
$label5.Size = $System_Drawing_Size
$label5.TabIndex = 12
$label5.Text = "Misc:"
 
$form1.Controls.Add($label5)
 
$label6.DataBindings.DefaultDataSourceUpdateMode = 0
 
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 12
$label6.Location = $System_Drawing_Point
$label6.Name = "label6"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 17
$System_Drawing_Size.Width = 200
$label6.Size = $System_Drawing_Size
$label6.TabIndex = 13
$label6.Text = "Search Folder Root:"
 
$form1.Controls.Add($label6)
 
$label4.DataBindings.DefaultDataSourceUpdateMode = 0
 
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X =703
$System_Drawing_Point.Y = 15
$label4.Location = $System_Drawing_Point
$label4.Name = "label4"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 46
$label4.Size = $System_Drawing_Size
$label4.TabIndex = 11
$label4.Text = "Tags:"
 
$form1.Controls.Add($label4)
 
$label3.DataBindings.DefaultDataSourceUpdateMode = 0
 
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 484
$System_Drawing_Point.Y = 41
$label3.Location = $System_Drawing_Point
$label3.Name = "label3"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 64
$label3.Size = $System_Drawing_Size
$label3.TabIndex = 10
$label3.Text = "Description:"
 
$form1.Controls.Add($label3)
 
[System.Environment+SpecialFolder]$SearchRoot="MyDocuments"
$fldBrowser.RootFolder = $SearchRoot
 
$label2.DataBindings.DefaultDataSourceUpdateMode = 0
 
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 507
$System_Drawing_Point.Y = 12
$label2.Location = $System_Drawing_Point
$label2.Name = "label2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 41
$label2.Size = $System_Drawing_Size
$label2.TabIndex = 9
$label2.Text = "Author:"
 
$form1.Controls.Add($label2)
 
$label1.DataBindings.DefaultDataSourceUpdateMode = 0
 
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 310
$System_Drawing_Point.Y = 15
$label1.Location = $System_Drawing_Point
$label1.Name = "label1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 60
$label1.Size = $System_Drawing_Size
$label1.TabIndex = 8
$label1.Text = "All Fields:"
 
$form1.Controls.Add($label1)
 
$txtTag.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X =755
$System_Drawing_Point.Y = 12
$txtTag.Location = $System_Drawing_Point
$txtTag.Name = "txtTag"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 100
$txtTag.Size = $System_Drawing_Size
$txtTag.TabIndex = 7
 
$form1.Controls.Add($txtTag)
 
$txtMisc.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 755
$System_Drawing_Point.Y = 35
$txtMisc.Location = $System_Drawing_Point
$txtMisc.Name = "txtMisc"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 100
$txtMisc.Size = $System_Drawing_Size
$txtMisc.TabIndex = 6
 
$form1.Controls.Add($txtMisc)
 
$txtAuth.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 554
$System_Drawing_Point.Y = 12
$txtAuth.Location = $System_Drawing_Point
$txtAuth.Name = "txtAuth"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 100
$txtAuth.Size = $System_Drawing_Size
$txtAuth.TabIndex = 5
 
$form1.Controls.Add($txtAuth)
 
$txtDesc.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 554
$System_Drawing_Point.Y = 38
$txtDesc.Location = $System_Drawing_Point
$txtDesc.Name = "txtDesc"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 100
$txtDesc.Size = $System_Drawing_Size
$txtDesc.TabIndex = 4
 
$form1.Controls.Add($txtDesc)
 
$txtTerm.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 374
$System_Drawing_Point.Y = 12
$txtTerm.Location = $System_Drawing_Point
$txtTerm.Name = "txtTerm"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 100
$txtTerm.Size = $System_Drawing_Size
$txtTerm.TabIndex = 1
 
$form1.Controls.Add($txtTerm)
#endregion Generated Form Code
 
#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null
 
} #End Function
 
#Call the Function
GenerateForm
Categories: Miscellaneous, Powershell, Scripting Tags:

Powershell 3.0 – drool

September 21st, 2011 Mark A. Weaver No comments
Rating 3.00 out of 5

Okay, so if you live under a rock and haven’t heard, the CTP for the Windows Management Framework 3.0 has been released by Microsoft (http://www.microsoft.com/download/en/details.aspx?id=27548).

I know, you are probably thinking “Big Deal!!” another Community Tech Preview. Not so fast there… THIS CTP includes Powershell 3.0!

Let me restate: “THIS CTP INCLUDES POWERSHELL 3.0!”

What I hope to do is post more as I begin to learn about what is new, what is cool, what is fresh, etc.

A little story about me and Powershell 3.0 ….

When I found out about the Windows 8 – Developer Preview, I wasn’t excited about the new interface, the new look of familiar applications… no. After I found out how to actually get to a command prompt, my first thing was to run Powershell and do a:

$host.version

To my UTTER DELIGHT, I saw the number “3″ in the output. My colleagues, of course, we interested in why I was ooo-ing and ahhh-ing.. then they saw that I was sitting at a Powershell prompt (of course) and the “geek”, “nerd”, and “dork” comments began.

Anyway, needless to say, I soon discovered I could install Powershell 3 on my Windows 7, SP1 laptop at home so I prompty did so upon arriving home from work.

Wow…that was a longer little story than I was expecting.

The bottom line is that I finally have it installed and have begun playing with it and I am a TOTAL GEEK.

——————————

One of the things I was afraid of was losing my Powershell 2.0 installation, yet I had read that they could co-exist. Well, seeing is believing, and I am a believer now.

Launching “powershell.exe” from a command line, by default, will open up version 3.

Launching “powershell.exe -version 2″ from a command line will bring up version 2.

Yes, it really is that simple.

Upon a cursory glance at the cmdlets available I notice that there are many more geared toward command line management of the system and features.

get-controlpanelitem

show-controlpanelitem “Display”

get-counter

new-webbinding

Also there is a cmdlet that helps you explore all of the cmdlets available via a GUI:

show-command

I have, literally, been playing with the new powershell for about an hour, so stay tuned for more updates on this.

Please, everyone, go grab it, kick the tires, run it through its paces, and poke it with a stick.

As always, happy scripting and have a good time discovering Powershell 3.0.

— Mark

Tag, You’re It!

July 2nd, 2011 Mark A. Weaver Comments off
Rating 3.00 out of 5

This will be part one of two posts to talk about a few little scripts I have been working on to help me search through my script repository.

Using dropbox, I have created my own little script repository that is out in the “cloud”.  I didn’t know how much I would like it, but it certainly makes it easy for me and others on my team to share the same scripts.

Anyway…the thought behind this part was to have an easy way to “tag” my scripts with information that would make it easier to search all of the scripts I have been working on.

All it is basically doing is creating some well-formed comments that I could then parse out. As a safety precaution, this version makes a backup copy of the script before modifying it. If you don’t want to back it up, just comment out the following line:

	Copy-Item -Path $Script -Destination $BackupScriptPath -Force

Without further ado, here is the code:

 

 
##-------------------------------------------------------------------
## Script: Add-ScriptTags.ps1
## Written by: Mark A. Weaver 
## Website: vmweaver.com
## 
## Version: 1.0
## Creation Date: 7/2/2011
## Purpose: This script will be used to add the specified tags to a script file
##              It will prepend the tag data to the script text as commented strings.
## Markup Definitions:
##       _TAG:  - Comma-separated list of tag words
##	 _AUTH: - Text with Authors name
##       _DESC: - Text with Description  
##       _DATE: - DateTime text with last update
##       _VER:  - Version number
##       _MISC: - Miscellaneous information
##
##    
##   Input: 
##                      -Script "Path to Script you are tagging"
##                      -Auth "AUthor Name"
##                      -Tag "comma separated list of tags"
##			-Desc "Description of the script"
##			-Date "Date information"
##			-Ver "Script Version"
##			-Misc "Miscellaneous information you wish to include"
##          
##
##  Output: 
##	SCript is modified with the information. If this script is run multiple times, this 
##      information will be over-written.
##                 
##                              
##  Assumptions: 
##
##
##  Example:
##  	.\Add-ScriptTags.ps1 -Script ..\MyScript.ps1 -Auth "Mark A. Weaver" 
##            -Tag "Test,Foo,Blah" -Desc "Test Script" -Ver "1.2"              
##               
#############################
## Updates:
##    
##
##----------------------------------------------------------------------
 
param($Script=$(throw "Script to tag must be specified!"),$Tag, $Auth, $Desc, $Date,$Ver,$Misc)
 
if (Test-Path $Script) 
{
  $Contents = Get-Content $Script 
  [array]$PostMarkup = $Contents
 
	[array]$Markup = $Null
	$Markup += "################################"
	$Markup += "## _BEGINMARKUP"
	$Markup += "####"
	$Markup += "## _TAG:" + $Tag
	$Markup += "## _AUTH:"+ $Auth
	$Markup += "## _DESC:" + $Desc
	$Markup += "## _DATE:" + $Date
	$Markup += "## _VER:" + $Ver
	$Markup += "## _MISC:" + $Misc
	$Markup += "####"
	$Markup += "## _ENDMARKUP"
	$Markup += "################################"
 
 if ($Contents -match "_BEGINMARKUP") 
  {
	  $LineCount = 0
	  $BeginLine = 0
	  $EndLine = 0
	  Foreach($Line in $Contents)
	  {
 
	    if ($Line -imatch "_BEGINMARKUP") {$BeginLine = $LineCount - 1}
		if ($Line -imatch "_ENDMARKUP"){$EndLine = $LineCount + 1}
		 $LineCount += 1
       }
	  if ($BeginLine -eq 0)
	  {
	    [array]$PreMarkup = $Null
	  }
	  else
	  {
 
 
	   [array]$PreMarkup = $Contents[0..($BeginLine - 1)]
	  }
 
	  if ($EndLine -eq ($Contents.count -1))
	  {
         [array]$PostMarkup = $Null
	  }
	  else
	  {
	     [array]$PostMarkup = $Contents[($EndLine+1)..($Contents.count -1)]
	  }
   }
 
	$MarkedUpScript = $PreMarkup + $Markup + $PostMarkup
	$ScriptObject = Get-Item $Script
	$BackupName = "Backup_" + $ScriptObject.Name
	$BackupScriptPath = $ScriptObject.DirectoryName +"\"+ $BackupName
 
	Copy-Item -Path $Script -Destination $BackupScriptPath -Force
	Out-File -FilePath $Script -InputObject $MarkedupScript -Force
	Write-Host "--- Markup written to '$($Script)' ---" -ForegroundColor Green
	Write-Host "--- (Backup: '$($BackupName)') ---" -ForegroundColor DarkYellow
        $Markup | ForEach-Object{Write-Host $_ -ForegroundColor DarkGreen}
 
}
else
{
	Throw("Script file ""$Script"" does not exist.")
}

Hope this makes sense for you.. and stay tuned for the next post which will be on processing these files and searching a repository for scripts.
As always… Happy Scripting!
— Mark

Categories: Miscellaneous, Scripting Tags: