VBS Powershell Access 2016(64bit) + Windows 10 でAccess2.0のMDBファイルからテーブルとクエリを変換する

#コード
##Access2000ではありませんAccess95より古いAccess2.0を変換するというのがテーマです。
　[Access 2016(64 bit +win10Home)でmdbファイルは開ける MS Access 2013 Later can Open mdb file](https://qiita.com/Q11Q/items/a554aa07f1c25fbeb3f8)で紹介した通りAccess95までのMDBは変換できます。この中核の機能はcompactdatabaseです。
しかし、Access2.0はCompactdatabaseではエラーになります。そこで別の方法を使う必要があります。
 実際にAccess2.0のMDBが見つかったので、実験してみます。
##設定
###サンプルファイルのダウンロード、解凍
~~[できるAccess 2.0 Windows対応](http://dekiru.impress.co.jp/download/access2/index.htm)~~
https://web.archive.org/web/20070205023104/http://dekiru.impress.co.jp/download/access2/sample.exe
ここからexe形式(自己解凍形式)のファイルをダウンロードします。

~~ダブルクリックすると~~Windows10はLzh形式の自己解凍形式(拡張子exe)ファイルを開けなくなりました。Windows Defenderがお使いのバージョンのWindowsでは解凍できませんと表示します。そこで7zipをいれてください。7zipをいれて右クリックでメニューを表示し「ファイ名\フォルダに解凍」を選択します。途中で止まりますが、解凍は成功します。
解凍~~され~~すると、２つのファイルができます。
このうちURIAGE.MDBをDドライブのルートに置きます。
### 作業の流れ
Dドライブ直下においたURIAGE.MDB
を
DbsG.MDB
へ
テーブルはSelect Intoで
クエリはプロパティを抜き出す形で移行する
##フォーム、リレーションシップ、アクションマクロ、VBAのモジュールを確認する
MDBと同じ位置に
\testfile.txt
で展開する。

```visualbasic
Option Explicit
'32bit 強制起動
'http://scripting.cocolog-nifty.com/blog/2011/02/wsh6432bit-b32d.html

If InStr(LCase(WScript.FullName),"system32") Then 
If CreateObject("Scripting.FileSystemObject").FileExists(Replace(LCase(WScript.FullName),"system32","syswow64")) Then
  CreateObject("WScript.Shell").Run """" & Replace(LCase(WScript.FullName),"system32","syswow64") & """ """ & WScript.ScriptFullName & """"
  WScript.Quit
End If
End If

Const Dnm = "D:\"
Dim strMDB :strMDB = Dnm & "\URIAGE.MDB"
Dim stgMDB:stgMDB= Dnm & "\DbsG.MDB"
Const dbOpenDynamic=16 'ダイナセット タイプの Recordset を開きます。
Const dbOpenDynaset=2 'ダイナセット タイプの Recordset を開きます。
Const dbOpenForwardOnly = 8,dbOpenSnapshot =4,dbOpenTable=1
'前方スクロール タイプの Recordset を開きます。'スナップショット タイプの Recordset を開きます。'テーブル タイプの Recordset を開きます。 

'RecordsetOptionEnum 列挙 (DAO)
Const dbAppendOnly=8,dbConsistent=32,dbDenyRead=2,dbDenyWrite=1,dbExecDirect=2048,dbFailOnError=128,dbForwardOnly=256,dbInconsistent=16,dbReadOnly=4,dbRunAsync=1024,dbSeeChanges=512,dbSQLPassThrough=64
'AppendOnlyユーザーが新しいレコードをダイナセットに追加するのを許可しますが、既存のレコードを読み取ることは許可しません。dbConsistentダイナセット内の他のレコードに影響を与えないフィールドにのみ更新を適用します (ダイナセット タイプとスナップショット タイプのみ)。
'DenyRead他のユーザーが Recordset のレコードを読み取れないようにします (テーブル タイプのみ)。'DenyWrite他のユーザーが Recordset のレコードを変更できないようにします。
'ExecDirectSQLPrepare ODBC 関数を最初に呼び出さずに、クエリを実行します。dbFailOnErrorエラーが発生した場合、更新をロールバックします。
'ForwardOnly前方スクロールのみのスナップショット タイプ Recordset を作成します (スナップショット タイプのみ)。
'Inconsistent他のレコードに影響が及ぶ場合でも、すべてのダイナセット フィールドに更新を適用します (ダイナセット タイプとスナップショット タイプのみ)。
'ReadonlyRecordset を読み取り専用として開きます。
'dbRunASyncクエリを非同期で実行します。dbSeeChanges編集中のデータを別のユーザーが変更している場合、実行時エラーを生成します (ダイナセット タイプのみ)。
'ODBC データベースに SQL ステートメントを送信します (スナップショット タイプのみ)。
Const dbAttachedODBC=&H20000000,dbAttachedTable=&H40000000,dbAttachExclusive=&H10000,dbHiddenObject=1,dbSystemObject=&H80000002
Const dbVersion20=16,dbVersion10=1,dbVersion120=128,dbVersion11=8,dbEncrypt=2,dbDecrypt=4
Const dbVersion30 =32
Const dbVersion40 =64
'LanguageConstants 列挙 (DAO)(https://msdn.microsoft.com/ja-jp/library/office/ff821047.aspx)
Const dbLangGeneral = ";LANGID=0x0409;CP=1252;COUNTRY=0" '英語、ドイツ語、フランス語、ポルトガル語、イタリア語、および現代スペイン語
Const dbLangJapanese = ";LANGID=0x0411;CP=932;COUNTRY=0"
'LockTypeEnum 列挙 (DAO)
Const dbOptimistic=3,dbOptimisticBatch=5,dbPessimistic=2,dbOptimisticValue=1
'WorkspaceTypeEnum 列挙 (DAO)
Const dbUseJet = 2

'ADO Data Type
Const adBigInt=2,adBinary=128,adBoolean=11,adBSTR=8,adChar=129,adCurrency=6,adDate=7,adFileTime=64,adGUID=72,adInteger=3,adLongVarChar=201,adDBDate=133,adDBTime=134,adDBTimeStamp=135,adDecimal=4,adDouble=5
'Ado PositionEnum
Const adPosEOF=-3,adPosBOF=-2,adPosUnknown=-1 
'ADO CursorLocationEnum
Const adUseClient=3
'ADO CursorType
Const adOpenDynamic=2,adOpenForwardOnly =0,adOpenKeySet=1,adOpenStatic=3
With CreateObject("Scripting.Filesystemobject")
if .FileExists(Dnm & "\DBsG.MDB") Then .DeleteFile(Dnm & "\DBsG.MDB")
if .FileExists(Dnm & "\testfile.txt") Then .DeleteFile(Dnm & "\testfile.txt")
end with
Dim fso,ts :Set fso = CreateObject("Scripting.FileSystemObject"):set ts = fso.CreateTextFile(Dnm & "\testfile.txt", True)
Dim dbe :set dbe = CreateObject("DAO.DBEngine.36") 
Dim cDb : set cDb =dbe.OpenDatabase(strMDB)
Dim wrk :set wrk= dbe.workspaces(0)
Dim Db1 : set Db1= wrk.CreateDatabase(stgMDB,dbLangJapanese,dbVersion40)
Dim tdf ,Q,ctn,doc
ts.WriteLine("Tables List")
on Error Resume Next
For Each tdf In cDb.TableDefs

    If  LCase(Left(tdf.Name,4))<>"msys"  Then
   cdb.Execute ("Select [" & tdf.Name & "].* INTO [" & tdf.Name & "] In """ & stgMDB & """ FROM [" & tdf.Name & "];")
   ts.WriteLine(tdf.Name)
    End If

Next
ts.WriteLine("Query List")
For Each Q In cDb.QueryDefs
    If  LCase(Left(Q.Name,4))<>"msys"  Then
    Db1.CreateQueryDef Q.Name,Q.Sql
   ts.WriteLine(Q.Name & vbCrlf & Q.SQL)
    End If
Next
'参考[ＭＤＢオブジェクト一覧を取得する](http://tsware.jp/study/vol1/kaibo_01.htm)
  'レポートの一覧
ts.WriteLine("Report List")
  Set ctn = cDb.Containers(4)
  For Each doc In ctn.Documents
    ts.WriteLine(doc.Name)
Next
  'Formの一覧
ts.WriteLine("Form List")
  Set ctn = cDb.Containers(1)
  For Each doc In ctn.Documents
    ts.WriteLine(doc.Name)
Next
  'Macroの一覧
ts.WriteLine("Macro(Action Macro,Scripts) List")
  Set ctn = cDb.Containers(5)
  For Each doc In ctn.Documents
    ts.WriteLine(doc.Name)
Next
Dim fld,rel,buf
ts.WriteLine("Relationships List")
  Set ctn = cDb.Containers(3)
  For Each doc In ctn.Documents
    ts.WriteLine(doc.Name)
    set rel = cdb.Relations(doc.Name)
    buf =""
    buf = "+-Attributes:" & vbTab & rel.Attributes & vbCrLf & "+-ForeignTable:" & rel.ForeignTable & vbCrLf & "+-PartialReplica:" & rel.PartialReplica & vbCrLf  & "+-Name:" & rel.Name & vbCrLf & "+-MainTableName:" & rel.Table
    ts.WriteLine(buf)
    if rel.Fields.count > 0 Then
     ts.Writeline("+-Field List " & rel.Fields.count ) 
    For each fld In rel.Fields
     ts.WriteLine(vbTab & "+-fld.Name " & fld.Name & vbCrlf & vbTab & "+-fld.type" & fld.Type)
     Next
    end if
    set rel = Nothing
Next
ts.WriteLine("Sysrel List")
  Set ctn = cDb.Containers(6)
  For Each doc In ctn.Documents
    ts.WriteLine(doc.Name)
Next
  'Macroの一覧
ts.WriteLine("Macro(Action Macro,Scripts) List")
  Set ctn = cDb.Containers(5)
  For Each doc In ctn.Documents
    ts.WriteLine(doc.Name)
Next
  'Moduleの一覧
ts.WriteLine("Modules List")
  Set ctn = cDb.Containers(2)
  For Each doc In ctn.Documents
    ts.WriteLine(doc.Name)
Next
ts.close
wrk.close
cdb.close
Db1.close
set dbe = nothing
MsgBox "End"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/97bbb059-a8e3-e348-f1c1-c2d755975f86.png)

Access2.0形式のMDBファイルから、現在のmdbファイルに変換して、テーブルとクエリを得ることができた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/6483f41a-a1a0-59c4-3ca1-26d489fa1fe7.png)

#Point
##Access2.0形式にはCompactdatabeseが効かない。
Access2.0のMDBにCompactDatabaseをかけると一応MDBが作成される。だが、エラーでひらけない。このため、Access95までで通用する方法が全く適用できない。どうもこれもDao3.5を固定して参照しているのが原因ようだ。

##Access2.0形式はAccessでは開けない
　当然ながら、Access2016ではAccess2.0のmdbファイルを直接開くこともエラーが発生してできない。
　旧バージョンのAccess2007ってどこで入手できるのやら。
　必要ならフリーで提供するとかしないのか。

##VBSは32Bitで強制起動する
Dao3.6はこうしないと動かない
逆にDao12.0以降は64bitでないと開かない。
それだとAccess2.0 は開けない

##Workspaceに２つのデータベースを作る
##Workspaceとは
いま開いているデータベースがあると自動的にWorkspaces(0)ができている。
Access2016では特にこれを意識する必要性は全くない。旧バージョンの変換で必要になる程度。

さらにこのWorkspaceに新しいデータベースを作る
Access.Applicationではないためいろいろな制限がある。
本当はAccessAplicationで開きたいがAccess2.0形式は開けない。

##テーブルはシステムテーブルを除いて、Select Intoで複写
つまりSQLで複写しているためフィールドの細かいプロパティまでは複写できない。
ただしPowershellで詳細なオブジェクトのプロパティを見ることができるため、表示形式などの設定はそこで確認できる。

##クエリはプロパティからSQLと名前を複写
これでクエリ自体は作成できる。しかしクエリもテーブルと同様で細かいフィールドの設定は複写できない。プロパティを見て手動で打つしかない。

##それ以外のオブジェクトは名前のみ
###ConteinaersとDocumentを使う
[ＭＤＢオブジェクト一覧を取得する](http://tsware.jp/study/vol1/kaibo_01.htm)
しかし、ここで使っているContainers!Modulesのビックリマークは使えない。
しかし実は定数がある。たぶんそれを初めて解析したのは自分である。といっても0から7までの数字がContainersのどのオブジェクトに対応するかだけだったのだが。これにより、VBS、PowershellでもDocumentが使えるようになった。
Containers!Forms でまず各オブジェクトのコレクションを取得
For Eachで個別のオブジェクト***のDucuments***を取得。

###Documentsとは

>CurrentData および CurrentProject オブジェクトを理解する

> 以前のバージョンの Access では、DAO オブジェクトおよびそのメソッドとプロパティを使用してフォーム、レポート、マクロ、テーブル、フィールド、リレーション、およびクエリについての情報を取得することが可能です。たとえば、Document オブジェクトを使用して、データベースのテーブルおよびクエリの情報を取得できます。フォーム、レポート、スクリプト (Access マクロ)、テーブル (テーブルおよびクエリ)、およびモジュールは、それぞれ別の Container オブジェクトで表されます。各 Container オブジェクトには、現在のデータベースで指定されているすべての種類のオブジェクトを示す Document オブジェクトのコレクションが含まれます。各 Document オブジェクトには、***各オブジェクトについての要約情報のみが含まれており***、オブジェクトのプロパティまたはそれに含まれるデータにアクセスすることはできません。テーブルまたはクエリのデータで作業する場合は DAO Recordset オブジェクトを使用し、フォームおよびレポート自体で作業を行う場合は Forms または Reports コレクションのメンバを使用します。

Documentsとは各オブジェクトの要約情報(名前、最終更新日付など）のみなので、オブジェクトの中身まではつかめない。というか同名で意味が違うもの多すぎでは...なぜacDocumentにしなかったのか。

#Powershell
Powershellは正直遅いしエラー処理が大変だが、プロパティを吐き出させるにはこちらが楽である。
ついでにMDB形式だけではなくAccdb形式にも直接入れてみる。
##Newフォルダが削除されてしまうのでVBSでできたデータを移動させること。
名前違うのにすればよかった。
##とりあえずDドライブのルートにおいてください。

## Powershell(x86)で稼働させること
　やはり64bitではdao 3.6がエラーが出てしまう。Powerhsell ISE(x86)を使うのがいいとおもう。
　なお、その場合Set-ExecutionPolicy RemoteSigned -Scope Process -Force
をしないとスクリプトは動かない。

##モスキート音で聴力確認
　終了すると、3種類のBeep音がなるが一つは14000ヘルツ。モスキート音は15000くらいなので、これが聞こえないと耳が20代とは言われない。PCを稼働させて聴力を確認する。Powershellなら周波数が調整できるので可能だ。

```powershell
#Set-ExecutionPolicy RemoteSigned -Scope Process -Force

<#
Windows Powershell (ISE)(X86)でしか動きません This Script Only Run On Powershell (x86)
 この変換は日本語を想定しています。 Traspher Database Japanese
 If you want to Trasfer other language, Change setteing
$db1 = $wrk.CreateDatabase("D:\" + $nDbName,$dbLangJpn,$dbVer40)
$db2 = $dbe.CreateDatabase("D:\" + $nDbName2007,$dbLangJpn,$dbVer120)
以下の$Diで設定の下の既存フォルダファイルを削除します Delete followring Folder And Data
$Di setting drive in
\Ac2000.mdb
\Ac2007.mdb
\New
#>
CLS;
[DateTime]$Dt = get-date
###################################
### Drive And Files definision ####
###################################
$Di = "D:\"  # MDBがおかれているドライブかフォルダ　十分な空きをあるところにしてください
$ErrorActionPreference = "Stop"
Set-location $Di
#Source And TargetFile
$SrcDb = $Di + "\URIAGE.MDB" #変換の対象となるファイル名です。頭に\またはバックスラッシュをつけてください
$nDbName = "Ac2000.mdb"
$nDbFile = $Di + "\Ac2000.mdb"
$nDbFile2007 = $Di + "Ac2007.accdb"
$nDbName2007 = "Ac2007.accdb"
# 実行中のパス取得/移動
#   スクリプト名取得
$ScriptName = $MyInvocation.MyCommand.Name.replace(“.ps1”,“”)
#$ScriptName = “SYSTEM-GET”
###################################
### Delete Folder And Files    ####
###################################

try{
if(Test-Path (join-path $Di "new")){remove-item -path (join-path $Di "new")  -Recurse  -Force -ErrorAction SilentlyContinue}
if(Test-Path $nDbFile){remove-item $ndbfile -Force -ErrorAction SilentlyContinue}
if(Test-Path $nDbFile2007){remove-item $nDbFile2007 -Force -ErrorAction SilentlyContinue}
$folder = New-Item "\new" -itemType Directory -Force -ErrorAction SilentlyContinue
}Catch{
Write-Host $Error[0].Exception.Message
}

#[PowerShell を使ってテキストファイル読み込み/書きこみ](https://qiita.com/sukakako/items/ede96f6227f010a0f328)
$path = Split-Path -Parent $MyInvocation.MyCommand.Path
$WriteFileName = Join-path $folder  "Log.txt"
$Writefile = New-Object System.IO.StreamWriter($WriteFileName, $false, [System.Text.Encoding]::GetEncoding("UTF-8"))
$ObjectPrp =  Join-path $folder  "ObjectPrpeties.txt"
$Wrf2 = New-Object System.IO.StreamWriter($ObjectPrp, $false, [System.Text.Encoding]::GetEncoding("UTF-8"))
$wrf2.Close()
##################
### ENum Block ###
##################
$CrLF = "`n`r" #vbCrLf 改行の宣言 
$dbAttachedODBC=0x20000000;$dbAttachedTable=0x40000000;$dbAttachExclusive=0x10000;$dbHiddenObject=1;$dbSystemObject=0x80000002
#DAO.CommitTransOptionsEnum
$dbForceOSFlush = 1
#DAO.RecordsetOptionEnum
$dbFailOnError = 128
$dbOpenDynamic = 16  #ダイナセット タイプの Recordset を開きます。 
$dbOpenDynaset  =2 #ダイナセット タイプの Recordset を開きます。 
$dbOpenForwardOnly =8   #前方スクロール タイプの Recordset を開きます。 
$dbOpenSnapshot   =4  #スナップショット タイプの Recordset を開きます。 
$dbOpenTable   = 1 #テーブル タイプの

$dbLangGeneral = ';LANGID=0x0409;CP=1252;COUNTRY=0' #英語、ドイツ語、フランス語、ポルトガル語、イタリア語、および現代スペイン語
$dbLangJpn=';LANGID=0x0411;CP=923;COUNTRY=0'
$dbDecrypt=4  #最適化中にデータベースを復号化します。
$dbEncrypt=2 #データベースを暗号化します。 
$dbVersion10 =1 #Microsoft Jet データベース エンジン Version 1.0。
$dbVersion11 = 8 #Microsoft Jet データベース エンジン Version 1.1。
$dbVer20=0x10 #16d
$dbVer30=0x20 #32d Accesss 95/97
$dbVer40=0x40 #64d Access 2000 2002 2003
$dbver120=0x80 #128d Access 2007 0
$dbver140 = 0x100 #256d Access 2010
$dbver150 = 0x200 #512d Access 2015 
$dbVer167=0x400 #1024d Access 2016

$dbtxt=10;$tdbtxt="Text"
#DataTypeEnum 列挙 (DAO)
$dbBoolean=1;$tdbBoolean="YESNO"
$dbDate =8;$tdbDate="DATETIME"
$dbMemo=12;$tdbMemo="MEMO"
$adOpenStatic = 3  
$adLockOptimistic = 3  
$adOpenDynamic=2
#$Dao.Workspaces(0).Database(0).ContainersEnum
$ContainersDatabases = 0 #This is My setting Enumulation For Contaners
$ContainersForms = 1
$ContainersModules = 2
$ContainersRelShips=3
$ContainersReports=4
$ContainersScripts=5 # (Action) Macro
$ContainersSysRel = 6
$ContainersTables = 7
$tdf;$Q;$ctn;$acDocu
#####################################
### Create Database And Workspace ###
#####################################
$dbe=New-Object -ComObject DAO.DBEngine.36
Try{
$cDB = $dbe.OpenDatabase($SrcDb)
$wrk = $dbe.Workspaces(0)
$db1 = $wrk.CreateDatabase("D:\" + $nDbName,$dbLangJpn,$dbVer40)
$db2 = $dbe.CreateDatabase("D:\" + $nDbName2007,$dbLangJpn,$dbVer120)
}Catch{
if(!($db1 -eq $null)){ $db1.close()}
if(!($db2 -eq $null)){$db2.close()}
$cDB.Close()
$wrk.close()
$WriteFile.Close()
Write-Host $Error[0].Exception.Message
}
#////////////////////
### Table SQL Copy Select Into Double Database  
#///////////////////
$Cmd = "////#################################////" + $CrLF +"##########Table File Property Infomation ###############" + $CrLF + "##########################################";Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
if($cdb.TableDefs.count -gt 0){
$cmd = "Tabledefs List (include system table) " + "Total " + $cdb.TableDefs.count + "---------------";Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
ForEach($tdf In $cDB.TableDefs){
$tdf.Name | Format-List | Out-File $ObjectPrp -Encoding utf8 -Append
}
}
$cmd = "Tabledefs List (include system table) End ---------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append

ForEach($tdf In $cDB.TableDefs){
If(!($tdf.name -like "Msys*" )){
$cDB.Execute("Select [" + $tdf.Name + "].* INTO [" + $tdf.Name + "] In """ + $db1.Name + """ FROM [" + $tdf.Name + "];")
$cDB.Execute("Select [" + $tdf.Name + "].* INTO [" + $tdf.Name + "] In """ + $db2.Name + """ FROM [" + $tdf.Name + "];")}

$WriteFile.WriteLine($tdf.name)
$Writefile.WriteLine("Select [" + $tdf.Name + "].* INTO [" + $tdf.Name + "] In """ + $db1.Name + """ FROM [" + $tdf.Name + "];")
$Writefile.WriteLine("Select [" + $tdf.Name + "].* INTO [" + $tdf.Name + "] In """ + $db2.Name + """ FROM [" + $tdf.Name + "];")
$prps = $tdf.properties
ForEach($prp In $prps){
$cmd = $tdf.name 
$cmd = $tdf.Name +" " + "Properties list"
Out-File $ObjectPrp -InputObject $cmd  -Encoding utf8 -Append
$prp | Format-List | Out-File $ObjectPrp -Encoding utf8 -Append}
foreach($prp in $flds.properties){
$Writefile.WriteLine($tdf.name + ":" + $fld.name +":" + $prp.name)
 $cmd = gm -InputObject $fldPrps -MemberType all
 $cmd | Format-list |Out-File $ObjectPrp  -Encoding utf8 -Append 
$flds = $tdf.fields
$cmd= $tdf.Name + " "+ "Field Property " + $CrLF;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
foreach($fld in $flds){
$fldPrps = $fld.properties
$cmd = $tdf.name +" "+ $fld.name + " Fieldproperty" + $CrLF ; Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
foreach($fldprp in $fldprps){
$cmd = gm $fldprp -MemberType all
$cmd | Format-List | Out-File $ObjectPrp -Encoding utf8 -Append}
}
$cmd = $tdf.name +" "+ $fld.name + " Fieldproperty End >-------" + $CrLF ; Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append     
}
}

#////////////////////
### Query SQL Copy 
#///////////////////
$Cmd = "////#################################////" + $CrLF +"##########Q uery List  ######################" + $CrLF + "##########################################";Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
Foreach($Q In $cDB.QueryDefs){
if($Q.Type -eq 0){
$db1.CreateQueryDef($Q.Name,$Q.SQL)
$db2.CreateQueryDef($Q.Name,$Q.SQL)
$prps = $Q.Properties
$cmd = $Q.Name +" " + "Properties list" + $CrLF
Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
Foreach($prp in $prps){
$prp.Properties | Format-List | Out-File $ObjectPrp -Encoding utf8 -Append
}
$cmd = $Q.Name +" " + "Field Property list" + $CrLF
Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
$flds = $Q.Fields
foreach($fld in $flds){
$fldPrps = $fld.Properties
$cmd = $tdf.name +" "+ $fld.name + " Fieldproperty" + $CrLF
foreach($fldPrp in $fldPrps){
#$cmd = gm $fldPrp -MemberType all
$fldPrp | Format-List | Out-File $ObjectPrp -Encoding utf8 -Append}
} 
}
}
#////////////////////
### Collection Properties 
#///////////////////
Try{
sl $folder
$tdfs= $cdb.TableDefs
$Qs=$cdb.QueryDefs
$DE36Prp = $dbe.Properties
$Dbprps = $cdb.Properties
$Rels = $cdb.Relations
$DE36Prp>"De36.txt"
$cdb > "Dbproperty.txt"
$tdfs >"tdfs.txt"
$Qs >"Queries.txt"
$Rels>"Rels.txt"
}Catch{
if(!($db1 -eq $null)){ $db1.close()}
if(!($db2 -eq $null)){$db2.close()}
$cDB.Close()
$wrk.close()
$WriteFile.Close()
Write-Host $Error[0].Exception.Message
}
#////////////////////
### Object Properties
#///////////////////
#Formの一覧
$Cmd = "##########################################" + $CrLF + "##########################################";Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
$writefile.WriteLine("Form List")
$cmd= "Forms List ---------------------------" + $CrLF
Out-File $ObjectPrp -InputObject $cmd    -Encoding utf8 -Append
Try{
   $ctn = $cDB.Containers($ContainersForms)
$cmd= "Form " +  $ctn.Name + " List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
ForEach($docu In $ctn.documents){
$cmd= "Form " +  $Docu.Name + " List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append

    $Writefile.WriteLine($docu.Name)
    $prps= $docu.Properties
      ForEach($prp In $prps){
       $cmd = gm -InputObject $prp -MemberType All
       $cmd | Format-List | Out-File $ObjectPrp  -Encoding utf8 -Append}
$cmd= "Forms List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
}# Next $docu
 }Catch{
 $ErrorActionPreference = "Continue";
 $Writefile.WriteLine("NO Form in this database")
}
#Reportの一覧
$Cmd = "##########################################" + $CrLF + "##########################################";Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
$writefile.WriteLine("Report List")
$cmd="*****Reports List *******" + $CrLF
Out-File $ObjectPrp -InputObject $cmd  -Encoding utf8 -Append
Try{ $ctn = $cDB.Containers($ContainersReports)
$cmd= "Reports " +  $ctn.Name + " List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
 
ForEach($docu In $ctn.documents){
$cmd= "Reports " +  $docu.Name + " List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append

    $Writefile.WriteLine($docu.Name)
    $cmd = "Reports Name " + $docu.Name + $CrLF 
Out-File $ObjectPrp -InputObject $cmd  -Encoding utf8 -Append
    $prps= $docu.Properties
    ForEach($prp In $prps){
    $cmd = gm -InputObject $prp -MemberType All
    $cmd | Format-list | Out-File $ObjectPrp -Encoding utf8 -Append}
$cmd= "Reports " + $docu.Name + " List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
}# Next $docu
}Catch{
 $ErrorActionPreference = "Continue";
 $Writefile.WriteLine("NO Form in this database")
}
#Scriptsの一覧
$Cmd = "##########################################" + $CrLF + "##########################################";Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
Try{$writefile.WriteLine("Action Macro Scripts List")
Out-File $ObjectPrp -InputObject "*****Script List *******" + $CrLF  -Append -Encoding utf8
$ctn = $cDB.Containers($ContainersScripts)
$cmd= "Scripts " +  $ctn.Name + " List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
ForEach($docu In $ctn.documents){
$cmd= "Scripts " +  $docu.Name + " List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append

    $Writefile.WriteLine($docu.Name)
    $cmd = "Script Name "+ $docu.Name + $CrLF
    Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
    $prps= $docu.Properties
    ForEach($prp In $prps){
    $cmd = gm -InputObject $prp -MemberType All
    $cmd | Format-list | Out-File $ObjectPrp -Encoding utf8 -Append}
$cmd= "Scripts" + $docu.name + "  List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
     }
 }Catch{
 $ErrorActionPreference = "Continue";
 $Writefile.WriteLine("NO Scripts in this database")}

#Moduleの一覧
$Cmd = "##########################################" + $CrLF + "##########################################";Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
$writefile.WriteLine("Modules List")
$cmd = "*****Modules List *******" + $CrLF
Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
$cmd= "Module " +  $ctn.Name + " List ---------------------------" + $CrLF ;Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append

Try{
  $ctn= $cDb.Containers($ContainersModules)
ForEach($docu In $ctn.documents){
    $Writefile.WriteLine($docu.Name)
    $cmd ="Module Name "+ $docu.Name +"---------"+ $CrLF ; Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
    $prps= $docu.Properties
    ForEach($prp In $prps){
    $cmd | Format-list | Out-File $ObjectPrp  -Encoding utf8 -Append
    $cmd ="Module Name "+ $docu.Name +" Property List ---------"+ $CrLF ; Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
    }
}
}Catch{$ErrorActionPreference = "Continue";$writefile.WriteLine("NO Module")}

#Relationshipsの一覧
$Cmd = "##########################################" + $CrLF + "##########################################";Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
$writefile.WriteLine("Relation Ships ------")
$cmd = "Relation Ships List ------------"  + $CrLF
Out-File $ObjectPrp -inputobject $cmd  -Encoding utf8 -Append
Try{
  $ctn= $cDb.Containers($ContainersRelShips)
ForEach($docu In $ctn.documents){
    $Writefile.WriteLine($docu.Name)
    $cmd =$docu.Name + "Relation----Fields--------" + $CrLF
    Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
    $rels = $cdb.Relations
    $rel= $Rels.Item($docu.Name)
    $cdm = gm -InputObject $rel -MemberType All
    Out-File -InputObject $cmd -FilePath $ObjectPrp -Append
    $cmd="Module Name "+ $docu.Name + "Relation----Prp--------" + $CrLF
    Out-File $ObjectPrp -InputObject $cmd -Encoding utf8 -Append
    $prps= $docu.Properties
    foreach($prp In $prps){
    $Writefile.WriteLine($prp.Name)
    $cmd = gm -InputObject $prp -MemberType all
    $cmd | Format-list | Out-File $ObjectPrp -Encoding utf8 -Append}
    $flds = $rel.fields
    $cmd =$docu.Name + "Relation----Fields--------" + $CrLF
    Out-File $ObjectPrp -InputObject $cmd   -Encoding utf8 -Append
    foreach($fld In $flds){
    $Writefile.WriteLine($fld.name)
    $fldPrps = $fld.properties
    $cmd = gm -InputObject $fldPrps -MemberType all
    $cmd | Format-list | Out-File $ObjectPrp  -Encoding utf8 -Append}
}
}Catch{ $ErrorActionPreference = "Continue"; $writefile.WriteLine("NO Mocule")}
###################
### END Block   ###
###################
Try{
$db1.Close()
$db2.Close()
$cDB.Close()
$wrk.close()
$WriteFile.Close()
}
Catch{
 $ErrorActionPreference = "Continue"
Write-Host $Error[0].Exception.Message
Write-Host "End"
}Finally{
 [Console]::Beep(262,700);[Console]::Beep(750,500);[console]::beep(14000,900)
 Write-host Date - $dt
Write-Host "End"
}
Write-host (New-timespan $dt (Get-Date)).TotalMilliseconds
```

#参考文献
##Powershell
[エラー処理は大事Add Star](http://d.hatena.ne.jp/motie/20140620/1403284005)
$ErrorActionPreference
 -ErrorAction:Stop 
[PowerShell を使ってテキストファイル読み込み/書きこみ](https://qiita.com/sukakako/items/ede96f6227f010a0f328)
[PowerShellの落とし穴！ForEach-Objectとforeachは違う？](https://cheshire-wara.com/powershell/ps-column/foreach-object-statement/}
この記述からForeach In においては-Begin が使えないと判断した。

[PowerShellでビープ音の「ドレミの歌」を奏でてみよう](http://tech.guitarrapc.com/entry/2013/02/05/000226)
[PowerShell 実践 経過時間の取得](http://www.sakutyuu.com/technology/?p=131)

##おまけ
余談このころは郵便番号が5桁なので5桁と3桁が混在するのはデータベース的には大変で
120-
120-22
のように並ぶのは、見た目がシュール。
あとオブジェクトのプロパティに、しきりと
TypeName   : System.__ComObject#{00000027-0000-0010-8000-00aa006d2ea4}
というのが出てくるが、これがDao3.5らしい。
このため、このままMDBが読み込めるとすると、
「次のクラスは登録されていません。次のCLSIDのオブジェクトを参照してください。
:{00000010-0000-0010-8000-00AA006D2EA4}」エラーが出て起動できない。
[VB覚書](https://blogs.yahoo.co.jp/qrhck723/3586701.html)
どおりでもう開けないというはずである。
おそらくCompactDatabaseはDao3.5の参照設定を変換することはできないのだろう。
たとえCompactdatabseで変換してもAccessがDao3.5の参照設定ではねているものと考えられる。

##その他
[Access2.0のMDBファイルをExcel2013で開く - 家庭部PC科 2017/4/23](http://fanblogs.jp/honeycome/archive/93/0)
JET 4.0を使ってテーブルだけ救出する。
しかしこれは64bitでは使えそうにない。
それにこの方法はクエリが救出できない。
>###Access2.0アプリケーション
>こんにちは、ハニービーンです。
>　私の仕事先では、いまだに稼働しているAccess2.0アプリケーションがあり、データの入力が日々行われています。
>　しかし、このアプリケーションは、かなり昔にWindows3.1環境で開発され、しかも作成者不明という代物です。このためにスタンドアローンのWindowsXP機が1台残されていて、そこで稼働されているという状況です。

>そのWindowXP機も撤去することになったため、新たなプログラムを作成してそちらに作業を引き取ることになりました。
>###古いMDBファイルのデータ
>新たなプログラムに移行するのはよいとして、旧アプリケーションで作成された何年分にもわたる入力済みのデータを破棄するわけにはいかないので、データも移行する必要があります。
 - Excel2013を起動し、MDBファイルを開きます。
 - セキュリティに関する通知が表示されたら「有効にする」を選択します。
 - [接続]タブの「データソース」の文字列をコピーする
 - 「プロバイダー」タブを開き、「Microsoft Jet 4.0 OLE DB Provider」を選択します。
 - 「接続」タブに戻ると、「データソース」の文字列が空になっているので、先ほどコピーした内容をペーストします。
 
目を疑うような記述だ。本当に2.0形式なのか?なぜ今まで変換しなかったのか?とりあえず確かなことはこの方法は32BITのExcelでしか有効ではないということだ。64BITではDAO3.6も参照設定ができない。oledb 12.0 oledb 16.0も接続できないのである。
####さらに補足するとこの記事のやり方では開けない
実験する時間がなくてすごく遅くなったのだが、最新のExcel2016では、この記事のやり方を真似たいと思ったが、Microsoft Jet 4.0 OLE DB Providerが出てこないためむりなようだ。セキュリティをさげ、開けるファイルを増やしても現れない。当然ドライバは入れている。64bitversionのAccess2016であり、これではJetを完全に追い出しているようだ。
この状況では、むしろテーブルとクエリを救える可能性がある分、VBScriptの方がよいと思われる。Documentまではいけるのでもう少しだと思うのだが。なにかロックがかかったような挙動で「前のバージョンで作成されたので開けません」というメッセージが出る。

##自己解凍形式補足
https://dekiru.net/article/13419/
https://web.archive.org/web/20190809233429/https://dekiru.net/article/13419/
2016.01.05 Tue 20:50 
>Windows 10では、ZIP形式とLZH形式で圧縮されたファイルであれば、［圧縮フォルダーツール］タブから簡単に展開（解凍）できます。

http://faq.mypage.otsuka-shokai.co.jp/app/answers/detail/a_id/288308/~/%5Bwindows10%5D-creators-update%E9%81%A9%E7%94%A8%E5%BE%8C%E3%81%8B%E3%82%89lzh%E5%BD%A2%E5%BC%8F%E3%81%AE%E5%9C%A7%E7%B8%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8C%E9%96%8B%E3%81%91%E3%81%AA%E3%81%84
https://web.archive.org/save/http://faq.mypage.otsuka-shokai.co.jp/app/answers/detail/a_id/288308/~/%5Bwindows10%5D-creators-update%E9%81%A9%E7%94%A8%E5%BE%8C%E3%81%8B%E3%82%89lzh%E5%BD%A2%E5%BC%8F%E3%81%AE%E5%9C%A7%E7%B8%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8C%E9%96%8B%E3%81%91%E3%81%AA%E3%81%84
>Windows 10のCreators Updateを適用したOS（ビルド 1703）ではLZH形式の圧縮ファイルの展開がWindowsの標準でサポートされなくなりました。
そのため、Creators Updateを適用後からLZH形式の圧縮ファイルが白抜きの不明なアイコンに変化し、開くことが出来なくなる場合があります。

LZH自体の取り扱いが2017になくなっている。LZHだけでなくLZHの自己解凍形式も扱えなくなるバージョンアップが2018年から2019年の間に行われ、これがDekiru.netの公開停止につながっているようだ。
---
#重要な記事Access2.0から2000へのアップグレードの記事を発掘
##必要性
現在のところテーブルとクエリくらいでモジュールは取り出せないが、本をみればAccess Basic棟が乗っているかもしれない。
また、Access95でもどこか共通するところがあると考える。
現在のAccessのVBAの定石である`Application.CurrentDb`がAccess 2000からということもこれで判明した。
しかし、これでもまだユニコード部分が足りない。
何が書いてあったのか不明である。
しかし、ここに出ているだけでもMissingLinkをかなり埋めている。
そして、Access2.0がなぜ使えなくなったのか。Windows10は16Bit命令を廃止しているからではないかと考えられる。
その根拠はAccess Basicが16BitAPIを使っているからである。

#旧バージョンからアップグレードする際のご注意（重要）
https://web.archive.org/web/20050319065324/http://www.microsoft.com/japan/Office/previous/2000/Access/techinfo/planning/caution.asp
最終更新日 : 9/29/2000
ここでは、旧バージョンのAccess より、Access 2000 に移行する際のポイントを記します。

##バージョンアップをしてはいけないケース
Access 2000 のデータベースは、下位互換性を備えていますが、旧バージョンの Access より Access 2000 形式のデータベースファイルを参照することは出来ません。
その為、複数のバージョンの Access にてデータベースファイルを参照する環境下においては、複数のバージョン内で最も古いバージョンに合わせて運用する必要があります。
もし、お使いの環境内で、古いバージョンの Access からもデータベースファイルを共有することがあるようならば、変換後は環境内にある Access のバージョンを Access 2000 に統一する必要があります。
##バックアップ
バージョンアップ作業を行う前に、万一のトラブルや、旧バージョンのソース保管等の意味も含めて、必ず現行バージョンのファイルをバックアップし、保管するようにしてください。
##すべてのモジュールのコンパイル
コンパイル時にエラーが発生するモジュールは、バージョンアップ時に変換エラーとなり、変換が出来ない場合があります。
その為、まず全てのモジュールをコンパイルし、コンパイルエラーが発生しないことを確認してください。

###！ 
全てのモジュールをコンパイルするには、まずいすれかのモジュールをオープンし、「すべてのモジュールのコンパイル」を実行します。
##修復
修復が必要なデータベースをバージョンアップすると、変換時エラーとなり、変換が出来ない可能性があります。
その為、修復の必要が無いと考えられる場合でも、トラブル回避のために修復作業を行ってください。 

#Access 2.0 のデータを Access 2000 にアップグレードする場合
最終更新日 : 9/21/2000

ここでは、Access 2.0 から、Access 2000 にバージョンアップする前に、確認しておくべきことや、修正作業を行う必要のあることについて解説します。

##Access 2.0 のデータを Access 2000 にアップグレードする場合

Access 2.0 から Access 2000 への変換は、16 Bit で作成されたコントロールで現在廃止されたものが存在します。大きな変更点としては、Access Basic が VBA に変更になった点、また、文字列の取り扱いが ANSI から Unicode に変更になった点などが挙げられます。
従って、ここではそれらの修正が主な作業となります。

修正作業は、まずデータ変換時にエラーとなる部分の修正を行い、そののちデータ変換作業を行います、最後に、実行時エラーとなる部分の修正を行います。

###アップグレード作業を行う前にするべきこと
アップグレード作業を行う前にするべきこと
最終更新日 : 9/29/2000
アップグレードを行う前に、まずファイル変換時エラーとなる部分の修正作業を行います。
この作業を行わないと、Access 2000 形式のデータに変換する作業でエラーとなるので気をつけて修正作業を行ってください。
ここでは、変換時エラーの原因となる部分と、その対処方法について記します。
アップグレード作業を行う前にするべきこと
<UL>
<li>文字列の比較についての注意事項
<li>プロパティ名についての注意事項
<li>バーコードコントロールを使用している場合の注意事項
<li>16bit の ActiveX コントロールを使用している場合の注意事項
<li>Compact Database メソッドを使った変換作業
</UL>
####文字列の比較についての注意事項

内容 ： 文字列の比較（別の文字列と見るか、同じ文字列と見るか）に次のような違いがあります。

|文字種 |例 |Access 2.0 |Access 2000|
|:------|:----|:------|:-------------|
|英大文字/小文字 |"ABC" と "abc"|	別文字列扱い |同文字列扱い|
|ひらがな/全角カタカナ/半角カタカナ|"データ" と "でーた" と"ﾃﾞｰﾀ"|別字扱い|同字扱い|

Access 2.0 において、ユニークな名前として付けたオブジェクト名が Access 2000 にバージョンアップする時点で、同一の名前とみなされて変換エラーが生じる可能性があります。
また、ユニーク値を必要とするフィールドで、データが重複しているとみなされエラーが生じる可能性があります。

対応 ： 変換以前において、オブジェクトの名前、ユニークな値としてのデータを見直し、該当する場合は修正してください。

#####プロパティ名
内容 ： Access 2000 では、コードで使用するプロパティ名に日本語名を使うことができません。

|プロパティ名 |例 |Access 2.0|Access 2000|
|:------|:----|:------|:-------------|
|英語 |Forms!部品カード.Caption |○ |○|
|日本語 |Forms!部品カード.標題 |○ |×|

対応 ： 変換以前において、日本語のプロパティをすべて英語に直してください。

#####バーコード コントロール
　
適用範囲：Access 2.0
内容：Access 2.0 のバーコード コントロールは、Access 2000 では使用できません。変換エラーが生じる可能性があります。
対応：変換以前にバーコード コントロールを削除し、変換後に [挿入] メニューの [ActiveX] で、あらためてバーコード コントロールを追加してください。
　
##### ActiveX コントロール
　
内容 ：16 ビットのActiveX コントロールは、Access 2000 では機能しない可能性があります。ActiveX コントロールの変換時にエラーが生じる可能性があります。
対応：事前に ActiveX コントロール（16 ビット）を削除し、変換後に [挿入] メニューの [ActiveX] で、対応する ActiveX コントロール（32 ビット）を追加してください。

##### CompactDatabase メソッドによる変換
　
内容：データベース変換に ConpactDatabase メソッドを使用することは出来ません。
対応： ツールバーのメニューより 「変換」 を選択して 変換を行ってください。
###アップグレード作業の手順
https://web.archive.org/web/20050319100721/http://www.microsoft.com/japan/Office/previous/2000/Access/techinfo/planning/process.asp
最終更新日 : 9/25/2000

アップグレード作業を行う前に必要な修正作業が終わったら、実際のファイル変換処理を行います。
もし、ここで変換時エラーが起きるようならば、「アップグレード作業をおこなう前にするべきこと」や
「旧バージョンからアップグレードする際のご注意（重要）」の内容をもう一度確認してみてください。
また、併せて「変換時のトラブルシューティング」を参照してください。

アップグレード作業の手順
変換は、Access 2000 を起動し、目的とする旧バージョンのデータベース ファイル（.mdbファイル）を開く時点で、ユーザーとの対話で行われます。
Access 2000 を起動します。

目的とする旧バージョンのデータベース ファイルを開きます。
[データベースを変換/開く] ダイアログ ボックスが表示されます。

データベースを変換] をクリックし、[OK] をクリックします。
[変換先データベース] ダイアログ ボックスが表示されます。

新しいファイル名を入力し、[保存] をクリックします。
変換後のデータベースが起動し、そのデータベース ウィンドウが表示されます。

###アップグレード作業の後に行うべきこと
http://www.microsoft.com/japan/Office/previous/2000/Access/techinfo/planning/after.asp
最終更新日 : 9/29/2000

Access 2000 への変換作業が終了した後は、実行時エラーなどになる Access 2000 との非互換部分の修正作業を行います。
Access 2.0 では Access Basic が採用されていましたが、Access 2000 では この部分が VBA となります、従って、この部分の修正作業が主な作業となります。
## プロシージャ
<UL>
<li>カレントデータベースの参照
<li>レコードセット（テーブル型）
<li>レコードセット（ダイナセット型）
<li>レコードセット（スナップショット型）
<li>フィールドの参照
<li>関数によって返される文字列の長さの値
</UL>
最終更新日 : 9/29/2000

アプリケーションがプロシージャを含む場合の変更を以下に記します。
###データベースへのアクセス
　

####カレント データベースの参照
Access 2.0

```vb
Dim db As DatabaseSet db=DBEngine.Workspaces(0).Databases(0)
```

Access 2000

```vb
Dim db As Database Set db=CurrentDb
```

####レコードセットを得る
レコードセットの型を設定する定数が変更になっています。

レコードセット（テーブル型）

```vb
Dim rs As RecordsetSet rs=db.OpenRecordset("テーブル名",DB_OPEN_TABLE)

```

[OldConstants 列挙型](https://docs.microsoft.com/ja-jp/office/vba/access/concepts/miscellaneous/oldconstants-enumeration)
2017/06/08
適用先: Access 2013 | Access 2016

~~これらの~~この定数は、Microsoft Access 2.0 との下位互換性を維持するために残されています。

Access 2000

```vb
Dim rs As Recordset Set rs=db.OpenRecordset("テーブル名",dbOpenTable)
```

　
####レコードセット（ダイナセット型）
Access 2.0

```vb
Dim rs As RecordsetSet rs=db.OpenRecordset("テーブル名他",DB_OPEN_DYNASET)
```

Access 2000

```vb
Dim rs As Recordset Set rs=db.OpenRecordset("テーブル名他",dbOpenDynaset)
```
　
####レコードセット（スナップショット型）
Access 2.0

```vb
Dim rs As RecordsetSet rs =db.OpenRecordset("テーブル名他",DB_OPEN_SNAPSHOT)
```

Access 2000

```vb
Dim rs As Recordset Set rs=db.OpenRecordset("テーブル名他",dbOpenSnapshot) 
```
###フィールドの参照
ユーザーが付けた名前は、ピリオドでは参照できません。！を参照子として使います。
編注:この記述からピリオドが先で！があとだとわかる。
####フィールドの参照

```vb
'Access 2.0 	
tbl.フィールド名 'ピリオドを使用
'Access 2000
rs!フィールド名
```
###文字列の長さ
####バイト文字の扱いを確認する
Access 2.0 で使われているAccess Basic と Access 95 以上（Access 2000 を含む）で使われるVisual Basic for Applications では、文字列操作関数が返す値が異なる場合が、あります。文字列の長さや文字コードそのものに依存するコーディングがある場合には、次の指針にしたがって手直しをしてください。

|関数使用例 |Access 2.0 |Access 2000|
|:----|:-------------|:----------|
|Len("A") |1 |1|
|Len("子") |1 |1|
|LenB("A") |1 |2|
|LenB("子") |2 |2|
|Len("子w") |2 |2|
|LenB("子w") |3|4|
|LenB(strconv("子w",vbFromUnicode))|3|3|

####注意
この文字列の長さの原理は、たとえばLeft、LeftB関数など一連の文字列操作関数に対応となります。したがって、Access 2.0 において、日本語（全角文字）の長さを２バイトと想定してプログラムを組んでいる場合には、Access 95 以降で正しくない結果を生じます。Access 2.0 からバージョンアップしたプロシージャの中で、文字列の長さを判定している場面で、返される値を同じにして働かせるには、次のようにします。 
|ケース|対応方法|
|:----|:-------------|
|半角だけで構成される文字列の長さ|Len のままで変更なし|
|全角だけで構成される文字列の長さ|LenB関数に変更|
|全角、半角混在の文字列の長さ|LenB(strconv("文字列",vbFromUnicode)) に変更|

## 実行時エラーとなるコード
<UL>
<li>書式プロパティについて
<li>モジュール内の半角カタカナについて
<li>Shell 関数について
<li>ODBC 接続について
<li>API について
<li>コンボボックスと Null 値について
<li>レポートの余白について
<li>ウィザードで作成した、他のアプリケーションを呼び出すコマンドボタンについて
<li>読取専用、レコード無しフォームのコントロールの参照
<li>半角カタカナの取り扱いについて
</UL>
###"書式" プロパティ

内容:コントロールの "書式" プロパティに設定した Null と長さ0の文字列（""）(編注:現在のvbNullString)を区別して表示する設定は、Access 2000 では働きません。
対応:コントロールの "コントロール ソース" プロパティに、IIf関数 を作成してください。
Nullでは Null、長さ0の文字列では ZLS、それ以外では入力された値が表示されます。
対応例:=IIf(IsNull([MyField]),"Null",Format([MyField],"@;ZLS"))

###モジュール内の半角カタカナ

内容:Access 2.0 では、半角カタカナのフィールド名をモジュール内で参照する場合に問題はありませんでした。
実行時にエラーになります。
対応:半角カタカナのフィールド名を [ ] で囲んでください。
###Shell関数

内容:Access 2.0では、Shell 関数の返す値は整数でした。Access 2.0では、長整数が返されます。
対応:Shell 関数の返す値を受け入れる変数を長整数にしてください

###ODBC接続

内容 :Access 2.0 では、16 ビット ODBC を使用しています。Access 2000 では、ODBC 接続エラーが発生します。
対応:32 ビットODBC を使ってください。

###API

内容:Access 2.0 では、16 ビットの API を使用していました。実行時にエラーが発生します。
対応:32 ビットAPI を使ってください。

###コンボ ボックスと Null 値

内容:"入力チェック" プロパティを "はい" に設定し、そのリストに Null を含まない場合においても Null が入ってしまいます。
Access 2.0 では、リストに Null が含まれない限り Null を入れることはできませんでした。
対応:Null を拒絶するのであれば、コントロールの "値要求" プロパティを "はい" に設定してください。

###レポートの余白

内容:レポートの「余白=0」の設定は、「余白=既定のプリンタの最小余白」に変更されます。
対応:レポートのコントロールを再配置し、すべてのコントロールが印刷範囲に収まるようにします。
　
###ウィザードで作成した、他のアプリケーションを呼び出すコマンド ボタン
　
内容:コマンド ボタン ウィザードで作成した、他のアプリケーションを呼び出すコマンド ボタンを実行するとエラーになります。
対応:コマンド ボタンをいったん削除し、Access 2000 のコマンド ボタン ウィザードで作成し直してください。
　
###読み取り専用、レコードなしフォームのコントロールの参照
　
内容:読み取り専用のフォームでレコードソースにレコードがない場合に、コントロールの値を参照するとエラーが発生します。
Access 2.0 では、Null が返されます。
対応:`On Error` によるエラー処理を追加記述してください。
###半角カタカナの扱い方
　
内容：以前のバージョンの Access では、コード中で半角カタカナの変数名やコントロール名を使用できましたが、
Access 2000 では VBA のコード中の半角カタカナと全角カタカナは区別しません。
したがって、半角カタカナの取り扱い方には十分な注意が必要です。
対応：以下の Q&A を参考にしてください。

Q. オブジェクト名（テーブル、クエリー、フォーム、レポート、マクロ、 モジュール）に半角カタカナは使用できますか？
A. 問題無く使用できます。ただし、オブジェクト名の半角カタカナ、全角カタカナは区別しません。
つまり半角カタカナの「テーブル」と全角カタカナの「テーブル」は、同じ名前として扱われます。
Q. データに半角カタカナを使用できますか？
A. 問題無く使用できます。

Q. テーブルのフィールド名に半角カタカナを使用できますか？
A. テーブルのフィールド名に半角カタカナを使用することは問題ありませんが、以下の点に注意する必要があります。
モジュール内でレコードセットのフィールド名として使用する場合。
以前のバージョンでは、次のように記述しても構いませんでしたが、
レコードセット変数名!半角カタカナフィールド名

Access 2000 で記述する場合は次のようにカタカナナフィールド名を [ ] で囲む必要があります。
レコードセット変数名![半角カタカナフィールド名]

Q. VBA のコード内に半角カタカナを使用できますか？
A. コード内で定数、コメントとして使用された半角カタカナは、問題無く使用できます。
変数名、定数名、プロシージャ名として入力された半角カタカナは、全角カタカナに自動的に正規化されます。

Q. 以前のバージョンの MDB ファイルを Access 7.0 データベースに変換した場合、
半角カタカナを全角カタカナに自動的に置き換えてくれますか？
A. 残念ながら Access 1.1 および、Access 2.0 で使用されていた半角カタカナのうち、
上記仕様変更により使用できなくなった部分（コントロール名、コード内の変数名、定数名、プロシージャ名として使用）は、
自動的に置き換えてくれません。データベース変換の事前処理、または、事後処理として、変換していただく必要があります。