Hey, Scripting Guy! How Can I Create a Database with More Than One Table?

ScriptingGuy1

Hey, Scripting Guy! Question

Hey, Scripting Guy! Being able to create a database from a script is nice, and I appreciated your article yesterday. But I need to have a database with more than one table in it. Obviously this can be done, but I am at a loss as to how to go about it. I am not a real programmer; do you have any tips for me?.

– GF

SpacerHey, Scripting Guy! Answer

Hi GF,

You need to do what? Sorry not really paying attention. I am watching The Guild on MSN. Dude, those people need to get a life. Speaking of having a life, back when I was a network administrator, I worked all the time doing repetitive tasks. It was not uncommon for me to put in 90 to 100 hours a week. I am not exaggerating at all. We actually had a thing we called the Centurion Club for people who worked more than 100 hours in a week. I was afraid I was going to become a lifetime member of that thing. One of the things I was always being called upon to do back then was create various databases for users, or to track data for inventory, auditing, and compliance checks. So this script should help you to gain control of both your network and your life.

This week we will be talking about scripting Microsoft Office Access. The Databases hub is a great jumping-off point because it highlights the available Office Access scripts we have in the TechNet Script Center. There are also links to the Office Access scripts we have in the Script Center Script Repository and on the Community-Submitted Scripts Center. When taken as a whole, there are tons of examples for you to review. For information about downloading and installing Windows PowerShell, you can go to the Windows PowerShell Scripting Hub.

The CreateAccessDataBaseAndMultipleTables.ps1 script is seen here.

Function Check-Path($Db)
{
 If(!(Test-Path -path (Split-Path -path $Db -parent)))
   {
     Throw "$(Split-Path -path $Db -parent) Does not Exist"
   }
  ELSE
  {
   If(Test-Path -Path $Db)
     {
      Throw "$db already exists"
     }
  }
} #End Check-Path
Function Create-DataBase($Db)
{
 $application = New-Object -ComObject Access.Application
 $application.NewCurrentDataBase($Db,10)
 $application.CloseCurrentDataBase()
 $application.Quit()
} #End Create-DataBase
Function Create-Table($tables)
{
 For($i = 0 ;  $i -le $tables.count -1 ; $i ++)
  {
   $TableElement = $tables[$i].split(",")
   $tableName = $tableElement[0]
   $fields = [string]::Join(",",$tableElement,1,$tableElement.Count-1)
   $command = "Create Table $tableName `($fields`)"
   Invoke-ADOCommand -db $Db -command $command
   $Fields=$null
  } #End For $i
} #End Create-Table
Function Invoke-ADOCommand($Db, $Command)
{
 $connection = New-Object -ComObject ADODB.Connection
 $connection.Open("Provider= Microsoft.Jet.OLEDB.4.0;Data Source=$Db" )
 $connection.Execute($command)
 $connection.Close()
} #End Invoke-ADOCommand
# *** Entry Point to Script ***
$Db = "C:\FSO\ComputerData.mdb"
$tables = Get-Content c:\fso\tables.txt
Check-Path -db $db
Create-DataBase -db $Db
Create-Table -tables $Tables

One way to create a couple of tables with multiple fields would be to essentially use exactly the same script we wrote yesterday.

We could then add some extra variables, and build the additional tables and fields. As seen here, we create two tables. The first table name is stored in the variable $table, and the second one in $table1. (Like all good computer things, we are zero based and that is why the second table is named $table1.) The fields for the first table are stored in $fields and the fields for the second table are store in $fields1. We then call the Invoke-ADOCommand function with each of the different commands. The code is seen here:

$Db = "C:\FSO\ComputerData.mdb"
$table = "Bios"
$table1 = "Video"
$Fields = "Record Counter, DateRun Date, SMBIOSBIOSVersion Text, Manufacturer Text, SerialNumber Text, Version Text"
$Fields1 = "Record Counter, DateRun Date, AdapterCompatibility Text, AdapterDACType Text, AdapterRAM Text, Description
Text, DriverDate Text, DriverVersion Text"
$command = "Create Table $table `($fields`)"
$command1 = "Create Table $table1 `($fields1`)"
Check-Path -db $db
Create-DataBase -db $Db
Invoke-ADOCommand -db $Db -command $command
Invoke-ADOCommand -db $db -command $command1

While the above approach works, and I have seen thousands of scripts written by students and others just learning to program that used this type of approach over the years, the problem is that it does not scale well at all. This is not to say that the approach is wrong; it may be perfectly acceptable for a quick one-off script, but it would require four new lines of code for each additional table you wish to create. The four lines that would need to be added are listed here:

$table = "Bios"
$Fields = "Record Counter, DateRun Date, SMBIOSBIOSVersion Text, Manufacturer Text, SerialNumber Text, Version Text"
$command = "Create Table $table `($fields`)"
Invoke-ADOCommand -db $Db -command $command

Clearly, we need a better approach. The better approach would use looping technology, which refer to language statements that make the code go in loops. Looping types of statements in Windows PowerShell include: for, foreach, do, do while, do until, and while. There is also the ForEach-Object cmdlet that performs looping for us when working within the Windows PowerShell pipeline. For more information about the basic syntax of these types of statements, check out the Windows PowerShell hub.

At first, I thought that I would place the table names and field names in a comma-separated values (CSV) file. This is seen in the image that follows this paragraph. The problem is we are basically back to the issue of hard-coded variables and names. We need to know how many columns we will have in our CSV file as we make our header columns for the file. If we were to limit ourselves to a fixed number of items, we are setting ourselves up for another Y2K disaster (unless you happen to be a Y2K remediation specialist, you don’t want to live through that fiasco again).

Image of a comma-separated values file with table names and field names

 

The better way to approach this issue is to use an array. The cool thing about an array is we can easily find out how many elements are in the array, and we can easily iterate through the collection of elements by using either the For statement or the ForEach statement. For more information about this basic technique, see the Microsoft Press book, Microsoft Windows PowerShell Step By Step.

Because of the way we wrote the script yesterday, we only need to add one additional function to allow us to read a text file, convert it into an array by using the split function, and then put it back together to create our new ADO command to allow us to create the table. The text file we will use is seen here:

Image of the text file we are using in this script

 

The first thing we need to do is to create the Create-Table function. Because the function will need to receive a text file that contains the table name and the fields, we specify an input parameter for the function. We use the Function keyword and follow the verb-noun naming convention that is used with Windows PowerShell cmdlets. After we are in the function, inside the script block (delineated by curly brackets) we begin a for loop to work with each line of the text that is in the $tables input variable. We will talk about how the $tables variable gets populated later. We use the count property minus one to tell us how many lines of text is contained in the $tables variable. This is because $tables is an array of text and it begins counting at zero. The last thing the for statement tells us is we will count by one. The ++ means add one to the value of $i each time we progress through the loop. This is all seen here:

Function Create-Table($tables)
{
 For($i = 0 ;  $i -le $tables.count -1 ; $i ++)

Next we take the line of text that is represented by the current place in the text file, and we use the split method to break it into an array. So we now have a text file that was broken into an array of lines. Now we are taking each line of the text file, and breaking it into an array that is separated by commas. We store this new array in the $TableElement variable:

$TableElement = $tables[$i].split(",")

After we have an array from the current line in the text file, we index into the array (that is we choose the item by element number) and select the first element. The first element in each line is the word we intend to use for the table name. We store this value in the variable named $tablename to make it easy to remember and to understand:

$tableName = $tableElement[0]

Now we need to put it back together. But we do not need the first element from the array. Because we have already used element 0 for the table name, we do not need a column in our database with the same name. In fact, we want the first column in the database to be a record number that is automatically created, but that is perhaps beside the point here. The cool thing is the static join method from the string class allows us to choose the starting point and the ending point in the array that we want to put back together. This is very powerful, and had no equivalent functionality in VBScript without writing your own function:

$fields = [string]::Join(",",$tableElement,1,$tableElement.Count-1)

Finally we create our ADO command and call the Invoke-ADOCommand function. We then clear out the value of the $fields variable to ensure that it is not polluted the next time through the loop. We then close out all the curly brackets. This is seen here:

$command = "Create Table $tableName `($fields`)"
   Invoke-ADOCommand -db $Db -command $command
   $Fields=$null
  } #End For $i
} #End Create-Table

The entry point to the script is where we initialize the variables and call the functions in the appropriate order. The path to the newly created database is specified in the $Db variable. The $tables variable is populated by using Get-Content to read the contents of the text file. We then check the path for the database, create the database, and then create the tables:

$Db = "C:\FSO\ComputerData.mdb"
$tables = Get-Content c:\fso\tables.txt
Check-Path -db $db
Create-DataBase -db $Db
Create-Table -tables $Tables

The newly created database is seen here:

Image of the newly created database

And so, GF, we come to the end of another “Hey, Scripting Guy!” article. Luckily, MSN allows you to pause things, so I did not miss much of The Guild. Join us again tomorrow as Office Access Database Week continues. 

Ed Wilson and Craig Liebendorfer, Scripting Guys

0 comments

Discussion is closed.

Feedback usabilla icon