2012-03-29 31 views
1

目前,我建立多个阵列在PowerShell中,反而使代码的可移植性,我想使用XML文件作为管理的一个简单的(阅读更多万无一失的)方式,每个阵列如何服务其目的。PowerShell中,XML和阵列

阵列1的信息的主列表 - 含有ROWNUMBER,名称,保留和类型。我想为XML看起来像这样:

<?xml version="1.0" encoding="UTF-8"?> 
<ZipList> 
    <Backup RowID="1"> 
     <RowNbr>1</RowNbr> 
     <NameType>TargetBackup</NameType> 
     <Retention>10</Retention> 
     <FileType>Folder</FileType> 
    </Backup> 
    <Backup RowID="2"> 
     <RowNbr>2</RowNbr> 
     <NameType>SourceBackup</NameType> 
     <Retention>7</Retention> 
     <FileType>Folder</FileType> 
    </Backup> 
    <Backup RowID="3"> 
     <RowNbr>3</RowNbr> 
     <NameType>XMLBackup</NameType> 
     <Retention>21</Retention> 
     <FileType>File</FileType> 
    </Backup> 
</ZipList> 

我目前构建的阵列我使用环通它以后,并从以及建立哈希表。所以,我真的不想重新设计其余的p​​owershell脚本。

但是,由于更改XML文件更容易(与更改脚本内的数组相比更容易),我所要做的就是将此数组复制到一个更直接的XML文件中&自我记录进行更改,读取此xml文件,然后将其存储在我当前创建的数组中。

我能得到XML文件中读取,但我遇到麻烦的XML数据到一个数组。对于上面的XML实例中,阵列是这样的:

counter ++ 
arr1 += ,@(counter,1,"TargetBackup",10,"Folder") 
counter ++ 
arr1 += ,@(counter,2,"SourceBackup",7,"Folder") 
counter ++ 
arr1 += ,@(counter,3,"XMLBackup",21,"File") 

等等....

我遇到的问题是,XML数据中,但它是一个字符串,我除了一次抓住所有东西之外别无他法。任何帮助,建议表示赞赏。

回答

2

为什么不直接将该数组导出为clixml。然后它是可移植的,当你想在你的脚本中使用它时,只需重新导入它,你就可以恢复阵列了。

+0

最初,我做到了。 XML中的结构和命名约定并不是很丰富,我不认为它们可以定制,或者至少不容易。 – 2012-03-29 16:35:01

+1

看你的数据,我不能说我看到任何一个XML格式提供您不能使用.csv文件获取,这将是更容易处理脚本的内外。恕我直言。 – mjolinor 2012-03-29 17:15:41

+0

我甚至没有考虑过 - 你是110%正确的。感谢您提出我未曾考虑的明显解决方案。 – 2012-03-29 18:13:11

1

正如跟进,以下是我所做的代码。 Mjolinor的建议使用简化的(相对而言)CSV文件的解决方案极大(感谢您)的。我当然试图让解决方案太复杂。

我创造了我用来驱动过程中的三个CSV文件中。首先是RotateBackups_Masterlist.txt文件。 BackupName是备份的名称,因为它在后续过程中与之关联。 VersionsRetained是要保持的数字。 BackupType是它是文件还是文件夹备份。

RowNbr,BackupName,VersionsRetained,BackupType 
1,TargetBackup,2,Folder 
2,LstDefBackup,5,File 
3,XMLBackup,3,File 
4,SourceBackup,2,Folder 
5,TXTBackup,8,File 

第二个文件是RotateBackups_FolderList.txt。 BackupName对应于上述文件中的相同字段,Foldername是要备份的文件夹。

RowNbr,BackupName,FolderName 
1,TargetBackup,c:\MyBooks\target 
2,SourceBackup,c:\MyBooks\source 

第三个文件是RotateBackups_FileExtensions.txt。 BackupName对应于第一个文件中的相同字段,FileExtension是要备份的文件的通配名称(它也将接受模式),而FolderLoc是要找到这些项目的文件夹。

RowNbr,BackupName,FileExtension,FolderLoc 
1,LstDefBackup,*.def,c:\MyBooks\target 
2,LstDefBackup,*.lst,c:\MyBooks\target 
3,XMLBackup,*.xml,c:\MyBooks\target 
4,TXTBackup,*.txt,c:\MyBooks\rfiles 

请注意,相同的文件扩展名可以备份到多个备份名。此外,可以将多个文件夹分配给相同的BackupName和FileExtension。

作用:

  • 它的文件名创建与它的zip文件,这些文件的 BackupName场(主文件)的名字命名加上日期时间戳(所有 同一批次内)的文件夹。
  • 这些文件名都具有相同的BATCH日期时间戳,因此您将 知道以20120401_091500.zip结尾的所有备份均为 ,这些备份都是在同一次运行中创建的。
  • 它使您能够进行版本备份,并为您提供 时间点来恢复。
  • 它使您在管理备份空间 需求方面有一定的灵活性。它使您能够针对关键备份保留较长的保留时间 ,或者对较不重要的备份保留较短的保留时间。
  • 删除的项目可以被破坏性删除或回收。
  • 根据创建日期,您的备份不会老化。导致备份被标记为删除的唯一的 是新建的 ,它将计数放在要保留的数字上。

它不会做什么:

  • 我没有很多的错误在它的处理,比检查 空数组或LASTEXITCODE之前立即删除文件等。
  • 这并不意味着同一类型的文件的庞大的数字是 备份使用的文件扩展名,如备份是一个-AT-A-时间 函数调用创建/更新一个zip文件。

最后,该做的工作的代码(张贴在全部意见后)。我从很多来源获取了许多部分代码,并感谢他们每个人的原始海报/开发人员。使用此实用程序需要您自担风险。我欢迎其他人可能希望补充的任何改进。

这是创建备份的功能。

function create-7zip([String] $aDirectory, [String] $aZipfile){ 
    [string]$pathToZipExe = "C:\Program Files\7-zip\7z.exe"; 
    [Array]$arguments = "a", "-tzip", "$aZipfile", "$aDirectory", "-r"; 
    & $pathToZipExe $arguments; 
} 
# Call it by using: 
#create-7zip "c:\temp\myFolder" "c:\temp\myFolder.zip" 

变量&数组初始化这里,从上面的文本文件都在这里进口。变量$ KillOrRecycle设置为回收站,所以删除的任何内容都会回收站。杀死是一个破坏性的,不可恢复的文件删除。

#************************************************************************************ 
#************************************************************************************ 
# Initialize variables 
$zipFolder = "C:\ZipFiles" 
$nameConv = "{0:yyyyMMdd_HHmmss}" -f (Get-Date) + ".zip" 
$fileList = @{} 
$FileCountArray = @() 
$bkupTypeArr = @() 
$myDocFolder = "c:\Documents and Settings\MyPC\My Documents\" 

# Import text files for master, folder and file backup information 
$bkupRotateMasterArr = Import-Csv $myDocFolder"RotateBackups_MasterList.txt" 
$fldrBkupArray = Import-Csv $myDocFolder"RotateBackups_FolderList.txt" 
$fileExtBkupArr = Import-Csv $myDocFolder"RotateBackups_FileExtensions.txt" 

# Switch to delete Item or to send to recycle bin 
#  delete is destructive and cannot recover file. 
#  Recycle setting removes file from folder, but sends to recycle bin 
#  and can be restored if needed. 
#  Must be either "Kill" or "Recycle" 
$KillOrRecycle = "Recycle" 
#************************************************************************************ 
#************************************************************************************ 

装入导入的CSV文件的内容为哈希表。
$ bkup_Counts是BackupName的散列表&要保留的文件数。

$ bkupTypeArr是BackupNames的阵列(稍后使用)

$ fArray是BackupName的散列表和文件名生成一个与它相关联。
$ nameConv在顶部完成,为此运行中的所有文件提供相同的日期时间戳。

# Load contents of master backup array 
$bkup_Counts = @{} 
$b = $null 
foreach($b in $bkupRotateMasterArr) 
    { 
    $bkup_Counts[$b.BackupName] = $b.VersionsRetained 
    } 


#set Backup Types from the array we just defined 
$type = $null 
foreach ($type in $bkup_Counts.Keys) { 
    $bkupTypeArr += $type 
    } 

#create array of our filenames for this batch 
$type = $null 
$fArray = @{} 
foreach ($type in $bkupRotateMasterArr) { 
    $fArray[$type.BackupName] = ($type.BackupName + $nameConv) 
     } 

接下来,如果我们有fileExtension阵列中的任何数据,通过它使用的文件夹位置&文件扩展名运行(递归)抓住一切事情,从路径匹配它,它与适当的BackupName关联。这增加了$文件列表中的哈希表具有FullName属性为关键,并作为值与相关联的BackupName。

# if extension array not null, get list of files to back up 
if ($fileExtBkupArr) {  
    # Gather the list of files to be backed up 
    $f = $null 
    foreach ($f in $fileExtBkupArr) { 
      $arr = @() 
      $arr = (Get-ChildItem $f.FolderLoc -Recurse -Include $f.FileExtension | Select-Object fullname) 
      foreach ($a in $arr) { 
       if ($a) { 
       $fileList[$a] = $f.BackupName 
       } # if $a not null 
      } # end inner foreach 
     } # end outer foreach 
} # if FileExtension Backup Array not null 

然后,如果filelist散列表上有任何内容,请将其压缩到适当命名的备份。

# if filelist count gt zero, then create zip file of them for appropriate backup 
if ($fileList.Count -gt 0) { # must have entries in hashtable 
    $f = $null 
    #Loop thru file list & associate file with the appropriate backup 
    foreach ($f in $fileList.Keys) { 
     $arcFile = $null 
     if ($fileList.ContainsKey($f)) { 
      if ($fArray.ContainsKey($fileList[$f])) { 
       $arcFile = $fArray[$fileList[$f]] 
       create-7zip $f.FullName $zipFolder\$arcFile 
      } #if key in fArray 
     } # if key in Filelist 
    } # end foreach 
} # if hastable not empty 

接下来,如果我们有要备份的文件夹,然后使用类似的过程来使用类似的方法备份这些文件夹。

# if folder backup not null then back up folders 
if ($fldrBkupArray) { # check if array not null (no entries) 
    $f = $null 
    #Backup Folders now 
    foreach ($f in $fldrBkupArray) { 
     $arcFldr = $null 
     #if ($fArray.ContainsKey($f[1])) { 
     if ($fArray.ContainsKey($f.BackupName)) { 
      $arcFldr = $fArray[$f.BackupName] 
      create-7zip $f.FolderName $zipFolder\$arcFldr 
      } #end if 
     } # end foreach 
} # end if $fldrBkupArray not null 

下一项是要确保我们在删除任何东西之前没有失败。我们根据归档位是否设置来删除,并将删除的文件发送到回收站(默认)或位桶。

# if 7zip succeeded, we'll continue 
if ($LASTEXITCODE -gt 0) 
    {Throw "7Zip failed" } 
ELSE { # if Exitcode = 0 then continue with job 
    # Remove any files with Archive bit = False 
    # we marked it for deletion in previous run 
    Add-Type -AssemblyName Microsoft.VisualBasic 
    $files=get-childitem -path $zipFolder 
    # we'll delete all files that don't have the archive bit set 
    Foreach($file in $files) { 
     If((Get-ItemProperty -Path $file.fullname).attributes -band [io.fileattributes]::archive) 
     { Write-output "$file is set to be retained" } 
     ELSE { 
      if ($KillOrRecycle = "Recycle") { 
       Write-output "$file does not have the archive bit set. Deleting (Sent to recycle bin)." 
       [Microsoft.VisualBasic.FileIO.Filesystem]::DeleteFile($file.fullname,'OnlyErrorDialogs','SendToRecycleBin') 
       $output = $_.ErrorDetails 
       } 
      ELSE { 
       Write-output "$file does not have the archive bit set. Deleting." 
       remove-item -recurse $file.fullname 
       $output =$_.ErrorDetails 
       } 
      } 
     } #end Foreach 

接下来,BackupName &计数导出到一个XML文件,在存档文件夹计数的文件(通过BackupName型),然后设置上的所有文件的存档位,所以我们可以标记多余的人删除。

# Export BackupCounts to XML 
$bkup_counts | Export-Clixml bkup_counts.xml 

# Get Number of ZIP files in folder 
$btype = $null 
foreach ($btype in $bkupTypeArr) { 
    $FileCountArray += ,@(($btype),(dir $zipFolder\$btype"*.zip").count) 
    } 

# Import BkupCounts from XML 
$bkup_Counts= Import-Clixml bkup_counts.xml 

# set Attribute byte on ALL files in zipfolder so we know we'll get the right ones 
attrib $zipFolder"\*" +a 

现在,回到通的bkup_Counts哈希表,从文件数的计数得到BackupName模式匹配的文件数,并减去保留的天。如果差异大于0,那么我们必须从该文件夹中删除那么多条目。

我们通过使用相同的图案BackupName管道的文件夹,在创建时间属性排序,然后选择第一N个文件,其中N是上面的保留值大于零的数目。

然后,对于我们选择的每个对象,请返回&将存档位设置为FALSE以将其标记为在下次运行时删除。

$row = $null 
    # Get LST & DEF filenames in array & display count 
    foreach ($row in $bkup_Counts.Keys) { 
     Get-ChildItem -Path $zipFolder -Include $row"*" -Recurse #| 
     (dir $zipFolder\$row"*".zip).count - $bkup_Counts[$row] 
     $delfiles = 0 
     $delfiles = (dir $zipFolder\$row"*".zip).count - $bkup_Counts[$row] 
     if ($delfiles -gt 0) { #sort folder by createdtime 
      # if more than specified nbr of backups present, un-archive excess ones to delete next run. 
      dir $zipFolder\$row"*" | sort-object -property {$_.CreationTime} | 
      select-object -first $delfiles | 
      foreach-object { attrib $_.FULLNAME -A} 
      } # end if delfiles gt 0 
     } # End foreach in bkup_counts 

} # End Else Last ExitCode = 0  

这里是整个代码。

function create-7zip([String] $aDirectory, [String] $aZipfile){ 
    [string]$pathToZipExe = "C:\Program Files\7-zip\7z.exe"; 
    [Array]$arguments = "a", "-tzip", "$aZipfile", "$aDirectory", "-r"; 
    & $pathToZipExe $arguments; 
} 
# Call it by using: 
#create-7zip "c:\temp\myFolder" "c:\temp\myFolder.zip" 

#************************************************************************************ 
#************************************************************************************ 
# Initialize variables 
$zipFolder = "C:\ZipFiles" 
$nameConv = "{0:yyyyMMdd_HHmmss}" -f (Get-Date) + ".zip" 
$fileList = @{} 
$FileCountArray = @() 
$bkupTypeArr = @() 
$myDocFolder = "c:\Documents and Settings\MyPC\My Documents\" 

# Import text files for master, folder and file backup information 
$bkupRotateMasterArr = Import-Csv $myDocFolder"RotateBackups_MasterList.txt" 
$fldrBkupArray = Import-Csv $myDocFolder"RotateBackups_FolderList.txt" 
$fileExtBkupArr = Import-Csv $myDocFolder"RotateBackups_FileExtensions.txt" 

# Switch to delete Item or to send to recycle bin 
#  delete is destructive and cannot recover file. 
#  Recycle setting removes file from folder, but sends to recycle bin 
#  and can be restored if needed. 
#  Must be either "Kill" or "Recycle" 
$KillOrRecycle = "Recycle" 
#************************************************************************************ 
#************************************************************************************ 

# Load contents of master backup array 
$bkup_Counts = @{} 
$b = $null 
foreach($b in $bkupRotateMasterArr) 
    { 
    $bkup_Counts[$b.BackupName] = $b.VersionsRetained 
    } 


#set Backup Types from the array we just defined 
$type = $null 
foreach ($type in $bkup_Counts.Keys) { 
    $bkupTypeArr += $type 
    } 

#create array of our filenames for this batch 
$type = $null 
$fArray = @{} 
foreach ($type in $bkupRotateMasterArr) { 
    $fArray[$type.BackupName] = ($type.BackupName + $nameConv) 
     } 

# if extension array not null, get list of files to back up 
if ($fileExtBkupArr) {  
    # Gather the list of files to be backed up 
    $f = $null 
    foreach ($f in $fileExtBkupArr) { 
      $arr = @() 
      $arr = (Get-ChildItem $f.FolderLoc -Recurse -Include $f.FileExtension | Select-Object fullname) 
      foreach ($a in $arr) { 
       if ($a) { 
       $fileList[$a] = $f.BackupName 
       } # if $a not null 
      } # end inner foreach 
     } # end outer foreach 
} # if FileExtension Backup Array not null 


# if filelist count gt zero, then create zip file of them for appropriate backup 
if ($fileList.Count -gt 0) { # must have entries in hashtable 
    $f = $null 
    #Loop thru file list & associate file with the appropriate backup 
    foreach ($f in $fileList.Keys) { 
     $arcFile = $null 
     if ($fileList.ContainsKey($f)) { 
      if ($fArray.ContainsKey($fileList[$f])) { 
       $arcFile = $fArray[$fileList[$f]] 
       create-7zip $f.FullName $zipFolder\$arcFile 
      } #if key in fArray 
     } # if key in Filelist 
    } # end foreach 
} # if hastable not empty 

# if folder backup not null then back up folders 
if ($fldrBkupArray) { # check if array not null (no entries) 
    $f = $null 
    #Backup Folders now 
    foreach ($f in $fldrBkupArray) { 
     $arcFldr = $null 
     #if ($fArray.ContainsKey($f[1])) { 
     if ($fArray.ContainsKey($f.BackupName)) { 
      $arcFldr = $fArray[$f.BackupName] 
      create-7zip $f.FolderName $zipFolder\$arcFldr 
      } #end if 
     } # end foreach 
} # end if $fldrBkupArray not null 


# if 7zip succeeded, we'll continue 
if ($LASTEXITCODE -gt 0) 
    {Throw "7Zip failed" } 
ELSE { # if Exitcode = 0 then continue with job 
    # Remove any files with Archive bit = False 
    # we marked it for deletion in previous run 
    Add-Type -AssemblyName Microsoft.VisualBasic 
    $files=get-childitem -path $zipFolder 
    # we'll delete all files that don't have the archive bit set 
    Foreach($file in $files) { 
     If((Get-ItemProperty -Path $file.fullname).attributes -band [io.fileattributes]::archive) 
     { Write-output "$file is set to be retained" } 
     ELSE { 
      if ($KillOrRecycle = "Recycle") { 
       Write-output "$file does not have the archive bit set. Deleting (Sent to recycle bin)." 
       [Microsoft.VisualBasic.FileIO.Filesystem]::DeleteFile($file.fullname,'OnlyErrorDialogs','SendToRecycleBin') 
       $output = $_.ErrorDetails 
       } 
      ELSE { 
       Write-output "$file does not have the archive bit set. Deleting." 
       remove-item -recurse $file.fullname 
       $output =$_.ErrorDetails 
       } 
      } 
     } #end Foreach 

    # Export BackupCounts to XML 
    $bkup_counts | Export-Clixml bkup_counts.xml 

    # Get Number of ZIP files in folder 
    $btype = $null 
    foreach ($btype in $bkupTypeArr) { 
     $FileCountArray += ,@(($btype),(dir $zipFolder\$btype"*.zip").count) 
     } 

    # Import BkupCounts from XML 
    $bkup_Counts= Import-Clixml bkup_counts.xml 

    # set Attribute byte on ALL files in zipfolder so we know we'll get the right ones 
    attrib $zipFolder"\*" +a 

    $row = $null 
    # Get LST & DEF filenames in array & display count 
    foreach ($row in $bkup_Counts.Keys) { 
     Get-ChildItem -Path $zipFolder -Include $row"*" -Recurse #| 
     (dir $zipFolder\$row"*".zip).count - $bkup_Counts[$row] 
     $delfiles = 0 
     $delfiles = (dir $zipFolder\$row"*".zip).count - $bkup_Counts[$row] 
     if ($delfiles -gt 0) { #sort folder by createdtime 
      # if more than specified nbr of backups present, un-archive excess ones to delete next run. 
      dir $zipFolder\$row"*" | sort-object -property {$_.CreationTime} | 
      select-object -first $delfiles | 
      foreach-object { attrib $_.FULLNAME -A} 
      } # end if delfiles gt 0 
     } # End foreach in bkup_counts 

} # End Else Last ExitCode = 0