DocsVisionデータベースの移行を自動化する

前文





どうやら-システムが閉じている場合、便利なツールがあるはずですか? まあ、または少なくともこれらの便利なツールを自分で作成するためのAPI。



残念ながら、通常はすべてが悪いです。ツールはありますが、その存在から非常に不便です。幸福はありません。 私たちは出なければなりません。



したがって、与えられた-システムDocsVision(以降DV)バージョン4.5 SR1。 そして、タスクは、あるサーバーから別のサーバーにデータベースを移動することです(顧客が新しいサーバーを購入したなど)。 この場合に発生する問題はまさに1つです。



データベースを新しい場所に移動する際のローカルアカウントのオブジェクトに対する権限は、カボチャに変わります。 また、標準DVグループはローカルであるため、問題を回避することはできません。



誰が興味を持っている-猫へようこそ。







標準ツール





まず、これらの目的のためにDocsVisionが提供するツールを検討してください。

dvprofessionals.blogspot.com/2010/03/blog-post_22.htmlで説明されています



これは私たちが必要とするもののように思えますが、一見しただけです。



画像



スクリーンショットからわかるように、一度に1つのレコードのみが記録されます。これは、数十のローカルアカウントの場合でも非常に不便です。 また、実際の経験に基づいて、ドメインのないクライアントは、ドメインのあるクライアントよりも頻繁に検出されます。 そしてこの場合-すべてのユーザーはローカルでサーバーに巻き込まれます。 そして、あなたの手で百または二つのアカウントを処理する-まったく笑っていない。



そのため、独自の何かを書くことが決定されました。



データベース構造研究





DocsVisionはクローズドプラットフォームであり、開発者に提供されるAPIのフレームワーク内でのみ文書化されます。 しかし、一部の情報はまだインターネット上にあり、十分であることが判明しました。



興味のある主なテーブルはdvsys_instancesdvsys_securityです。 1つ目はシステムのすべてのオブジェクト(カード、フォルダー、ディレクトリ、ファイルなど)に関する情報を含み、2つ目はシステムの情報を含みます。 さらに苦労せずに、セキュリティ記述子を保持します。 テーブルの構造を以下に示します。



画像

画像





テーブルは、dvsys_instances.SDIDおよびdvsys_security.IDフィールド によってリンクされてい ます 。 また、これらのテーブルのレコードの数は、権利の継承のおかげで非常に異なることに注意する必要があります。 たとえば、クライアントの1つでは、これらの値はそれぞれ277571と6639です。



そのため、タスクが設定されます-2番目のテーブルのすべての行を調べ、セキュリティ記述子をデコードし、必要なエントリの古いSIDを新しいものに置き換え、以前にエンコードしてから書き戻す必要があります。 さあ、始めましょう。



着想の実施





PowerShellが開発言語として選択されたのは、その助けを借りて必要なタスクのほとんどが簡単かつ自然に解決できるためです。



使いやすくするために、すべての設定は別のファイルに移動されました。 これらには、アカウント対応テーブルとデータベースアクセス設定が含まれます。



$SIDReplacement = @{ "S-1-5-21-2179127525-659978549-3108502893-1019" = "a31003\akushsky"; #akushsky "S-1-5-21-2179127525-659978549-3108502893-1016" = "a31003\ASPNET"; #ASPNET "S-1-5-21-2179127525-659978549-3108502893-1008" = "a31003\DocsVision Administrators"; #DV Administrators "S-1-5-21-2179127525-659978549-3108502893-1010" = "a31003\DocsVision Power Users"; #DV Power Users "S-1-5-21-2179127525-659978549-3108502893-1012" = "a31003\DocsVision Users"; #DV Users "S-1-5-21-2179127525-659978549-3108502893-1026" = "a31003\dobriy"; #DV Editors } $SQLServerName = "a31003" $SQLDatabaseName = "DV-BASE"
      
      







ターゲットサーバーでスクリプトを実行する方が論理的に思えたので、古いアカウントはSIDの形式で存在します(PowerShellを使用して取得することもできます、Googleはこれを知っています)。 そして新しいもの-スクリプトのプロセスで受け取るアカウントとそのSIDの形式で指定します。



また、開発プロセス中に判明したように、PowerShellはジェネリックオブジェクトのインスタンスを作成できません。そのため、Googleの腸からNew-GenericObject関数を取得する必要がありました。 私は彼女のコードを提供しません。記事の最後にリポジトリへのリンクがあります-すべてがそこにあります。



便宜上、スクリプトの実行中にログがコンソールに出力されるため、より便利な情報の蓄積のための構造を作成することにしました。



 # Struct for log add-type @" public struct DVObject { public string ID; public string Description; public string Accounts; } "@
      
      







最も完全なログを記録するには、もちろん、クエリはそれよりもはるかに多くの情報を返しますが、美しさには犠牲が必要です。



 SELECT I.InstanceID, I.Description, S.ID, S.SecurityDesc FROM [DV-BASE].[dbo].[dvsys_security] S LEFT JOIN [DV-BASE].[dbo].[dvsys_instances] I ON I.SDID = S.ID
      
      







したがって、同じ記述子を何度も処理しないように、識別子が書き込まれます。



 # Replace SDDL in each row only once $IDList = New-Object System.Collections.Generic.HashSet[Guid] ... # We need only one SQL-request for each ID if ($IDList.Contains($row["ID"])) {continue} else {$isOk = $IDList.Add($row["ID"])}
      
      







そして、楽しみが始まります。

  1. 結果のSecurityDescは、Base64でエンコードされたバイナリ文字シーケンスです。 また、SIDを置き換えるには、SDDL文字列を取得する必要があります。 形式の説明はMSDNにあります。 そして今、同じことを、コードだけで:



      # Convert SDDL from Base64 to binary form $ObjectWithSDDL = ([wmiclass]"Win32_SecurityDescriptorHelper") .BinarySDToSDDL([System.Convert]::FromBase64String($row["SecurityDesc"])) $sddl = $ObjectWithSDDL.SDDL
          
          





  2. 次に、SDDL文字列のSIDを使用して、対応表に従ってそれらをチェックアウトし、一致する場合はそれらを置き換えます。



      # Match all SIDs and replace [regex]::Matches($sddl,"(S(-\d+){2,8})") | sort index -desc | % { if ($SIDReplacement.ContainsKey($_.ToString())) { # Translate NT account name to SID $objUser = New-Object System.Security.Principal.NTAccount($SIDReplacement[$_.ToString()]) $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier]) # Replace it in SDDL $sddl = $sddl.Remove($_.index,$_.length) $sddl = $sddl.Insert($_.index,$strSID.Value) # Add to list of current object accounts $dvobject.Accounts += $SIDReplacement[$_.ToString()] $dvobject.Accounts += "`n" # Set replace completed $replaceComplete = $true } }
          
          





  3. 置換が行われた場合、逆のアクションを実行し、この変更をデータベースに書き込む必要があります。

      if ($replaceComplete) { # Add current info object to list $DVObjectList.Add($dvobject) $binarySDDL = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD($sddl).BinarySD $ret = [System.Convert]::ToBase64String($binarySDDL) ##### Update database ##### # Update query for currently replaced SDDL $SqlQuery = "UPDATE [dbo].[dvsys_security] SET Hash = '" + $binarySDDL.GetHashCode() + "', SecurityDesc = '" + $ret + "' WHERE ID = CONVERT(uniqueidentifier, '" + $row["ID"] + "')" # Attach query to command $UpdateSqlCmd.CommandText = $SqlQuery # Execute update query if ($UpdateSqlCmd.ExecuteNonQuery()) { Write-host "Update true for ID: " $row["ID"] } else { Write-host "Update false for ID: " $row["ID"] } }
          
          









したがって、すべての移行について、顧客のサーバー間、開発サーバーと顧客の間のユニバーサルメカニズムが取得されましたが、その方法はわかりません。



最終的には、約束どおり:記述されたコードを含むリポジトリへのリンク



All Articles