Advertisement
Old-Lost

AccessDB Module

May 11th, 2017
2,337
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # Functions for connecting to and working with Access databases
  2. # Original code by Matt Wilson (May 2009)
  3. # Modified extensively by Dale Thompson (Sept 2012)
  4. Set-StrictMode -Version Latest
  5.  
  6. # [system.reflection.assembly]::LoadWithPartialName("ADODB")
  7.  
  8. function Open-AccessDB {
  9.     <#
  10.     .SYNOPSIS
  11.     Opens an Access database
  12.     .DESCRIPTION
  13.     Opens an Access database
  14.     .PARAMETER Path
  15.     The file path to the database, which must exist
  16.     .EXAMPLE
  17.     $Conn = Open-AccessDB '\\amsfofil02\discipline\it\inventory(programs).accdb'
  18.     .INPUTS
  19.     None. You cannot pipe objects to this function.
  20.     .OUTPUTS
  21.     __ComObject
  22.     .LINK
  23.     Close-AccessRecordSet
  24.     Test-AcessDB
  25.     .NOTES
  26.     Author: Dale Thompson
  27.     LastEdit: 01/09/13
  28.     #Requires -Version 2.0
  29.     #>
  30.     [CmdletBinding()][OutputType([__ComObject])]
  31.     Param (
  32.         [Parameter(Position = 0, Mandatory = $true)][ValidateNotNullOrEmpty()][string]$Path
  33.     ) #param
  34.    
  35.     # Test to ensure valid path to database file was supplied
  36.     if (-not (Test-Path $Path)) {
  37.         throw "Invalid Access database path specified ($Path). Please supply full absolute path to database file!"
  38.     }
  39.     $FullPath = (Resolve-Path $Path).ProviderPath
  40.    
  41.     # TO-DO: Add check to ensure file is either MDB or ACCDB
  42.    
  43.     # Create a new ADO DB connection COM object, which will give us useful methods & properties such as "Execute"!
  44.     $Connection = New-Object -ComObject ADODB.Connection
  45.     try {
  46.         $Connection.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`"$FullPath`";Persist Security Info=False;")
  47. <#
  48.     # Actually open the database so we can start working with its contents
  49.     # Access 00-03 (MDB) format has a different connection string than 2007
  50.     if ((Split-Path $Path -Leaf) -match [regex]"\.mdb$") {
  51.         Write-Verbose "Access 2000-2003 format (MDB) detected!  Using Microsoft.Jet.OLEDB.4.0."
  52.         $AccessConnection.Provider = "Microsoft.Jet.OLEDB.4.0"
  53.     }
  54.  
  55.     # Here's the check for if 2007 connection is necessary
  56.     if ((Split-Path $Path -Leaf) -match [regex]"\.accdb$") {
  57.         Write-Verbose "Access 2007 format (ACCDB) detected!  Using Microsoft.Ace.OLEDB.12.0."
  58.         $AccessConnection.Provider = "Microsoft.ACE.OLEDB.12.0"
  59.     }
  60.     $AccessConnection.Open($Path)
  61. #>
  62.         $Connection
  63.     } catch { }
  64. }
  65.  
  66. function Test-AccessDB {
  67.     <#
  68.     .SYNOPSIS
  69.     Test that a database was opened properly
  70.     .DESCRIPTION
  71.     Test that a database was opened properly. If so, the connection object itself is sent down the pipeline.
  72.     .PARAMETER Connection
  73.     The connection to the database as returned by Open-AccessDB. Can be specified via the pipeline as well.
  74.     .EXAMPLE
  75.     Test-AccessDB $Connection
  76.     True
  77.  
  78.     This example tests the variable $Connection to see if it was opened properly.
  79.     .EXAMPLE
  80.     $Connection | Test-AccessDB
  81.     True
  82.  
  83.     This example demonstrates the variable $Connection to be specified via the pipeline.
  84.     .INPUTS
  85.     __ComObject
  86.     .OUTPUTS
  87.     __ComObject
  88.     .LINK
  89.     Open-AccessDB
  90.     Close-AccessRecordSet
  91.     .NOTES
  92.     Author: Dale Thompson
  93.     LastEdit: 01/09/13
  94.     #Requires -Version 2.0
  95.     #>
  96.     [CmdletBinding()][OutputType([__ComObject])]
  97.     Param (
  98.         [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)][ValidateNotNullOrEmpty()][__ComObject]$Connection
  99.     )
  100.     PROCESS {
  101.         try { if ($Connection.State -eq 1) { Write-Output $Connection } } catch { }
  102.     } # PROCESS
  103. } # Test-AccessDB
  104.  
  105. function Open-AccessRecordSet {
  106.     <#
  107.     .SYNOPSIS
  108.     Open an Access RecordSet
  109.     .DESCRIPTION
  110.     Returns an Access RecordSet object representing the query.
  111.     .PARAMETER Query
  112.     The SQL query, specified in standard MS Access SQL format
  113.     .PARAMETER Connection
  114.     The connection to the database as returned by Open-AccessDB
  115.     .PARAMETER CursorType
  116.     The CursorType attribute for the recordset. A number 0-3. Default is 3.
  117.     .PARAMETER LockType
  118.     The LockType attribute for the recordset. A number 1-4. Default is 3.
  119.     .EXAMPLE
  120.     $RecordSet = Open-AccessRecordSet 'SELECT * FROM Computers;' $Connection
  121.  
  122.     Gets all records and fields from the Computers table of the database $Connection.
  123.     .INPUTS
  124.     None. You cannot pipe objects to this function.
  125.     .OUTPUTS
  126.     __ComObject
  127.     .LINK
  128.     Close-AccessRecordSet
  129.     Test-AccessRecordSet
  130.     .NOTES
  131.     Author: Dale Thompson
  132.     LastEdit: 01/09/13
  133.     #Requires -Version 2.0
  134.     #>
  135.     [CmdletBinding()][OutputType([__ComObject])]
  136.     Param (
  137.         [Parameter(Position = 0, Mandatory = $true)][ValidateScript({ $_.Length -gt 1 })][string]$Query,
  138.         [Parameter(Position = 1, Mandatory = $true)][ValidateNotNullOrEmpty()][__ComObject]$Connection,
  139.         [Parameter(Position = 2)][ValidateSet(0, 1, 2, 3)][int]$CursorType = 3,
  140.         [Parameter(Position = 3)][ValidateSet(1, 2, 3, 4)][int]$LockType = 3
  141.     ) #param
  142.    
  143.     # Create the recordset object using the ADO DB COM object
  144.     $RecordSet = New-Object -ComObject ADODB.Recordset
  145.    
  146.     # Finally, go and get some records from the DB!
  147.     Write-Verbose "$Query, $($Connection.Provider), $CursorType, $LockType"
  148.     $RecordSet.Open($Query, $Connection, $CursorType, $LockType)
  149.     return ($RecordSet)
  150. }
  151.  
  152. function Test-AccessRecordSet {
  153.     <#
  154.     .SYNOPSIS
  155.     Test a RecordSet object
  156.     .DESCRIPTION
  157.     Tests an object as returned by Open-AccessRecordSet to see that it is a valid RecordSet and contains at least one record.
  158.  
  159.     If the object passes the tests it is sent down the pipeline.
  160.     .PARAMETER RecordSet
  161.     The RecordSet object to test
  162.     .EXAMPLE
  163.     Test-AccessRecordSet $RecordSet
  164.     True
  165.  
  166.     This examples tests the recordset stored in the variable $RecordSet.
  167.     .INPUTS
  168.     __ComObject
  169.     .OUTPUTS
  170.     __ComObject
  171.     .LINK
  172.     Close-AccessRecordSet
  173.     Open-AccessRecordSet
  174.     .NOTES
  175.     Author: Dale Thompson
  176.     LastEdit: 01/09/13
  177.     #Requires -Version 2.0
  178.     #>
  179.     [CmdletBinding()][OutputType([__ComObject])]
  180.     Param (
  181.         [Parameter(Position = 0, ValueFromPipeline = $true)][__ComObject]$RecordSet
  182.     )
  183.     PROCESS { try { if ($RecordSet.RecordCount -gt 0) { return $RecordSet } } catch { } }
  184. } # Test-AccessRecordSet
  185.  
  186. function Get-AccessRecordSetStructure {
  187.     <#
  188.     .SYNOPSIS
  189.     Get the structure of an Access RecordSet
  190.     .DESCRIPTION
  191.     Returns an array of PSObjects, one for each field present. Each PSObject contains the following NoteProperties:
  192.  
  193.         Name        - The Name of the field
  194.         Attributes  - The Attributes of the field
  195.         DefinedSize - The size of the field
  196.         Type        - The datatype of the field. The function Convert-AccessTypeCode can be used
  197.                       to convert from this number to a human-readable datatype
  198.  
  199.     .PARAMETER RecordSet
  200.     The RecordSet object from which to get the structure
  201.     .EXAMPLE
  202.     Get-AccessRecordSetStructure $RecordSet
  203.  
  204.     Name   Attributes DefinedSize Type
  205.     ----   ---------- ----------- ----
  206.     ID             90           4    3
  207.     Handle        102          32  202
  208.     Site          118           2    2
  209.     User          102          50  202
  210.  
  211.     This example shows the objects and properties of the recordset defined by the $RecordSet variable.
  212.     .INPUTS
  213.     None. You cannot pipe objects to this function.
  214.     .OUTPUTS
  215.     PSCustomObject[]
  216.     .LINK
  217.     Close-AccessRecordSet
  218.     Open-AccessRecordSet
  219.     Test-AccessRecordSet
  220.     .NOTES
  221.     Author: Dale Thompson
  222.     LastEdit: 01/09/13
  223.     #Requires -Version 2.0
  224.     #>
  225.     [CmdletBinding()]
  226.     Param (
  227.         [Parameter(Position = 0, Mandatory = $true)][ValidateNotNullOrEmpty()][__ComObject]$RecordSet
  228.     ) #param
  229.     PROCESS {
  230.         $RecordSet | Test-AccessRecordSet | % { $_.Fields | Select-Object Name, Attributes, DefinedSize, Type }
  231.     }
  232. }
  233.  
  234. function Convert-AccessRecordSetToPSObject {
  235.     <#
  236.     .SYNOPSIS
  237.     Converts an entire RecordSet to a set of PSCustomObjects
  238.     .DESCRIPTION
  239.     This Cmdlet cycles through the given RecordSet and creates a PSCustomObject for each record found. A NoteProperty is added for each field in the recordset, the Name being the field name, and the Value being the value out of that field from the recordset.
  240.     .PARAMETER RecordSet
  241.     The RecordSet object to convert
  242.     .EXAMPLE
  243.     $Computers = Convert-AccessRecordSetToPSObject $RecordSet
  244.  
  245.     Stores the names and values for each record in the recordset into NoteProperties of an array of PSCustomObjects.
  246.     .INPUTS
  247.     __ComObject
  248.     .OUTPUTS
  249.     PSCustomObject[]
  250.     .NOTES
  251.     Author: Dale Thompson
  252.     LastEdit: 10/11/13
  253.     #Requires -Version 2.0
  254.     #>
  255.     [CmdletBinding()][OutputType([PSCustomObject])]
  256.     Param (
  257.         [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)][ValidateNotNullOrEmpty()][__ComObject]$RecordSet
  258.     ) #param
  259.     BEGIN { $fields = Get-AccessRecordSetStructure $RecordSet }
  260.     PROCESS {
  261.         try { $RecordSet.MoveFirst() } catch { return }
  262.         do {
  263.             $record = @{ }
  264.             foreach ($field in $fields) {
  265.                 $record[$field.Name] = $RecordSet.Fields.Item($field.Name).Value
  266.             }
  267.             Write-Output ([PSCustomObject]$record)
  268.             $RecordSet.MoveNext()
  269.         } until ($RecordSet.EOF -eq $True)
  270.     }
  271. }
  272.  
  273. function Invoke-AccessSQLStatement {
  274.     <#
  275.     .SYNOPSIS
  276.     Executes a MS Acess SQL statement
  277.     .DESCRIPTION
  278.     Executes a MS Acess SQL statement against a database
  279.     .PARAMETER Query
  280.     The SQL query, specified in standard MS Access SQL format
  281.     .PARAMETER Connection
  282.     The connection to the database as returned by Open-AccessDB
  283.     .EXAMPLE
  284.     Invoke-AccessSQLStatement 'UPDATE Phones SET Phones.Location = 1312 WHERE (Phones.ID=3);' $Connection
  285.  
  286.     This examples updates the Phones table in the database represented by the $Connection variable.
  287.     .INPUTS
  288.     None. You cannot pipe objects to this function.
  289.     .OUTPUTS
  290.     Any. It's whatever the value of the SQL statement is.
  291.     .LINK
  292.     Open-AccessDB
  293.     .NOTES
  294.     Author: Dale Thompson
  295.     LastEdit: 01/09/13
  296.     #Requires -Version 2.0
  297.     #>
  298.     [CmdletBinding()]
  299.     Param (
  300.         [Parameter(Position = 0, Mandatory = $true)][ValidateNotNullOrEmpty()][string]$Query,
  301.         [Parameter(Position = 1, Mandatory = $true)][ValidateNotNullOrEmpty()][__ComObject]$Connection
  302.     ) #param
  303.     $Connection.Execute($Query)
  304. }
  305.  
  306. function Convert-AccessTypeCode {
  307.     <#
  308.     .SYNOPSIS
  309.     Converts an Access type code from and to a human-readable value
  310.     .DESCRIPTION
  311.     Every MS Access field in a recordset is a certain data type, and that type is stored in Access as a number. This Cmdlet tranlates that code to a label, and vis versa.
  312.  
  313.     Here are the possible values. You can use an item from either column and this function will return the corresponding value from the other column.
  314.  
  315.         Code  Label
  316.         ----  --------------
  317.         202   Text
  318.         203   Memo
  319.           7   Date/Time
  320.           6   Currency
  321.          11   Yes/No
  322.         205   OLE Object
  323.          17   Byte
  324.           2   Integer
  325.           3   Long Integer (also AutoNumber?!?)
  326.           4   Single
  327.           5   Double
  328.     .PARAMETER TypeCode
  329.     The code or label to get the corresponding value of
  330.     .EXAMPLE
  331.     Convert-AccessTypeCode 202
  332.     Text
  333.  
  334.     This example demonstrates returning the label corresponding to the MS Access type 202
  335.     .EXAMPLE
  336.     Convert-AccessTypeCode Text
  337.     202
  338.  
  339.     This example demonstrates returning the code corresponding to the label 'Text'
  340.     .INPUTS
  341.     System.String
  342.     .OUTPUTS
  343.     System.String
  344.     .NOTES
  345.     Author: Dale Thompson
  346.     LastEdit: 01/09/13
  347.     #Requires -Version 2.0
  348.     #>
  349.     [CmdletBinding()][OutputType([string])]
  350.     Param (
  351.         [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)][ValidateNotNullOrEmpty()][string]$TypeCode
  352.     ) #param
  353.     BEGIN {
  354.         # Build some lookup tables for our Access type codes so we can convert values pretty easily
  355.         $labelLookupHash = @{ "AutoNumber" = "3"; "Text" = "202"; "Memo" = "203"; "Date/Time" = "7"; "Currency" = "6"; "Yes/No" = "11"; "OLE Object" = "205"; "Byte" = "17"; "Integer" = "2"; "Long Integer" = "3"; "Single" = "4"; "Double" = "5" }
  356.         $codeLookupHash = @{
  357.             "202" = "Text"; "203" = "Memo"; "7" = "Date/Time"; "6" = "Currency"; "11" = "Yes/No"; `
  358.             "205" = "OLE Object"; "17" = "Byte"; "2" = "Integer"; "3" = "Long Integer"; "4" = "Single"; "5" = "Double"
  359.         }
  360.     }
  361.     PROCESS {
  362.         # Convert a value depending on what type of data was supplied
  363.         if ($TypeCode -match [regex]"^\d{1,3}$") {
  364.             $valueFound = $codeLookupHash.$TypeCode
  365.             if ($valueFound) {
  366.                 Write-Output $valueFound
  367.             } else { Write-Output "Unknown" }
  368.         } else {
  369.             $valueFound = $labelLookupHash.$TypeCode
  370.             if ($valueFound) {
  371.                 Write-Output $valueFound
  372.             } else { Write-Output "Unknown" }
  373.         }
  374.     }
  375. }
  376.  
  377. function Close-AccessRecordSet {
  378.     <#
  379.     .SYNOPSIS
  380.     Close an Access RecordSet or Database
  381.     .DESCRIPTION
  382.     This Cmdlet will close an Access RecordSet object or Database object.
  383.  
  384.     An alias for this Cmdlet is Close-AccessDB, as it handles both.
  385.     .PARAMETER RecordSet
  386.     The RecordSet or Database connection to close. An alias for this is Connection.
  387.     .EXAMPLE
  388.     Close-AccessRecordSet $RecordSet
  389.     .EXAMPLE
  390.     Close-AccessDB $Connection
  391.     .INPUTS
  392.     __ComObject
  393.     .OUTPUTS
  394.     None
  395.     .LINK
  396.     Open-AccessRecordSet
  397.     Test-AccessRecordSet
  398.     .NOTES
  399.     Author: Dale Thompson
  400.     LastEdit: 01/09/13
  401.     #Requires -Version 2.0
  402.     #>
  403.     [CmdletBinding()]
  404.     Param (
  405.         [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)][ValidateNotNullOrEmpty()][Alias('Connection')][__ComObject]$RecordSet
  406.     ) #param
  407.     try {
  408.         $RecordSet.Close()
  409.         [void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($RecordSet)
  410.     } catch { }
  411. }
  412.  
  413. Set-Alias Close-AccessDB Close-AccessRecordSet
  414.  
  415. Export-ModuleMember -Function Open-AccessDB, Test-AccessDB, Open-AccessRecordSet, Test-AccessRecordSet,
  416.                     Get-AccessRecordSetStructure, Convert-AccessRecordSetToPSObject, Invoke-AccessSQLStatement,
  417.                     Convert-AccessTypeCode, Close-AccessRecordSet -Alias Close-AccessDB
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement