Friday, April 23, 2010

Symantec Enterprise Vault

The following is a modified PowerShell script from Symantec to recall all the files from Vault if the file placeholder exist in the file server

## script attempt - comprehensive FSA script to analyze target locations and evaluate file within it
##
## First we check the registry to see if the bypassrecallimitsforadmins key (8.0) or bypassrecalllimitsforadmins (7.5 something where it was spelt right)
## We also check recalllimitmaxrecalls and recalllimittimeinterval to see if they are set to 99 and 1 respectively to give the best chance to recall all files if needed
## Note: while they may not choose to copy we will still get these values for later processing in case they do
##
## We will prompt for 2 locations: 1) the location of the fatr.exe executable & batch.cmd, and 2) the desired target path
## We will prompt for a decision if the user wants the placeholders that are verified as proper placeholders would also like them recalled (by copy to nul process)
## If they choose the copy option, we will report on the registry settings and recommend changes (and do them if they choose).
## Using these paths we will do the following
## 1) get a directory output of the target path and save that to a file named dirout.txt
## 2) using the dirout.txt file we will process each file in that list in the following manner
## 3) we will run fsutil (windows application) to confirm if the file has reparsepoint (placeholder) information, and if so, if the GUID matches the EV one (because of some issues found on 64 bit, this string has had the spaces removed to ensure matches on 64 and non-64 bit systems)
## *4) we will test the file as well with the fatr.exe application (in report mode) which will detail to us if the offline file bit is set or not
## 5) if the above tests result in finding a file which has the offline bit set, and NO reparse information, we will set the offline bit OFF (this will resolve the 'element not found errors' on archive attempts)
## 6) if the above tests result in finding a file which has the offline bit set, and EV reparse information, we will leave the file alone if copy choice is 'n' or copy the item to nul if 'y'
## 7) if the above tests result in finding a file which has the offline bit set, and reparse information (but not EV info), we will leave the file alone
## 8) if the above tests result in finding a file which has the offline bit unset, and NO reparse information, we will leave the file alone
## 9) if the above tests result in finding a file which has the offline bit unset, and EV reparse information, we will set the offline bit (this situation should not be found)
## 10) if the above tests result in finding a file which has the offline bit unset, and reparse information (but not EV info), we will leave the file alone
## 11) if the above tests result in finding not covered by the above we will report the results found and do nothing

##param

## ver.bat ($exepath = "$(read-host "Please enter the path to the fatr.exe & batch.cmd files. Use the format, :\, e.g. c:\testfolder ")",$tarpath = "$(read-host "Please enter the path to the desired target folder to analyze. Use the format, :\, e.g. c:\testfolder ")",$copyquestion = "$(read-host "If proper placeholders are found, would you like them recalled? Use the format y or n")")
$tarpath = $(read-host "Please enter the path to the desired target folder to analyze. Use the format, :\, e.g. c:\testfolder ")
$copyquestion = $(read-host "If proper placeholders are found, would you like them recalled? Use the format y or n")

## ------------------------------------------------
## Edited by Me (u know)
## ------------------------------------------------

$txtfile = $(read-host "Please enter the path to the file to search target. Use the format, :\\filename, e.g. c:\testfolder\file.txt")

## ------------------------------------------------

## $outpath = "$(read-host "Please enter the path for the output file. Use the format, :\, e.g. c:\testfolder ")" ## we should not need this line as output will be specified at run time.

$restart = 0
$script = $myinvocation.mycommand.definition
$exepath = split-path "$script"

##debug ##write-host $exepath
##debug ##write-host $tarpath
##debug ## write-host $tarpath

Write-Output "++++++++++++++++++++++++++++++++++" > $exepath\test1.txt
Write-Output "" >> $exepath\test1.txt
get-date out-file -filepath $exepath\test1.txt -append
Write-Output "Processing Started" >> $exepath\test1.txt
Write-Output "" >> $exepath\test1.txt


If ($copyquestion -eq 'y'){
Write-Output "Copy operation selected checking registry" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
$bol = test-path -path "HKLM:\SOFTWARE\Wow6432Node\KVS\Enterprise Vault\FSA\PlaceholderService"
$bol2 = test-path -path "HKLM:\SOFTWARE\KVS\Enterprise Vault\FSA\PlaceholderService"

If ($bol){
## 64 bit PHS
$testreg = get-itemproperty "HKLM:\SOFTWARE\Wow6432Node\KVS\Enterprise Vault\FSA\PlaceholderService"

If ($testreg.BypassRecalLimitsForAdmins -eq 1){
write-host "BypassRecalLimitsForAdmins is set (64 bit)"
write-output "BypassRecalLimitsForAdmins is set (64 bit)" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
}
Else{
$bypassnotset =$(read-host "The registry setting, BypassRecalLimitsForAdmins is not set, would you like to set it? Use the format y or n ")

If ($bypassnoteset = 'y'){
write-host "Setting BypassRecalLimitsForAdmins to 1"
write-output "Setting BypassRecalLimitsForAdmins to 1"
write-output "" >> $exepath\test1.txt
set-itemproperty -path "HKLM:\SOFTWARE\Wow6432Node\KVS\Enterprise Vault\FSA\PlaceholderService" -name "BypassRecalLimitsForAdmins" -value 1
$restart = 1
}
Else{
write-host "Not setting BypassRecalLimitsForAdmins can cause recall processing to fail if recall limits are encountered. Will exit. "
Break
}
}

If ($testreg.RecallLimitMaxRecalls -eq 99){
write-host "RecallLimitMaxrecalls is set to the highest accepted value (99) "
write-output "RecallLimitMaxrecalls is set to the highest accepted value (99) " >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
}
Else{
write-host "RecallLimitMaxrecalls is NOT set to the highest accepted value (99) "
$recalllimitnotset =$(read-host "The registry setting, RecallLimitMaxrecalls is not set to the highest acceptable value, would you like to set it? Use the format y or n ")

If ($recalllimitnotset = 'y'){
write-host "Setting RecallLimitMaxrecalls to 99"
write-output "Setting RecallLimitMaxrecalls to 99" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
set-itemproperty -path "HKLM:\SOFTWARE\Wow6432Node\KVS\Enterprise Vault\FSA\PlaceholderService" -name "RecallLimitMaxrecalls" -value 99
$restart = 1
}
Else{
write-host "Not setting RecallLimitMaxrecalls can cause recall processing to fail if recall limits are encountered. Will exit. "
Break
}
}

If ($testreg.RecallLimitTimeInterval -eq 1){
write-host "RecallLimitTimeInterval is set to the lowest accepted value (1) "
write-output "RecallLimitTimeInterval is set to the lowest accepted value (1) " >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
}
Else{
$recalllimitTnotset =$(read-host "The registry setting, RecallLimitTimeInterval is not set to the lowest acceptable value, would you like to set it? Use the format y or n ")

If ($recalllimitTnotset = 'y'){
write-host "Setting RecallLimitTimeInterval to 1"
write-output "Setting RecallLimitTimeInterval to 1" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
set-itemproperty -path "HKLM:\SOFTWARE\Wow6432Node\KVS\Enterprise Vault\FSA\PlaceholderService" -name "RecallLimitTimeInterval" -value 1
$restart = 1
}
Else{
write-host "Not setting RecallLimitTimeInterval can cause recall processing to fail if recall limits are encountered. Will exit. "
Break
}
}
}
ElseIf ($bol2){
## 32 bit PHS
$testreg = get-itemproperty "HKLM:\SOFTWARE\KVS\Enterprise Vault\FSA\PlaceholderService"
$eval1 = $testreg.BypassRecalLimitsForAdmins

## debug ##
write-host $eval1
If ($eval1 -eq 1){
write-host "BypassRecalLimitsForAdmins is set"
write-output "BypassRecalLimitsForAdmins is set" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
}
Else{
$bypassnotset =$(read-host "The registry setting, BypassRecalLimitsForAdmins is not set, would you like to set it? Use the format y or n ")

If ($bypassnoteset = 'y'){
write-host "Setting BypassRecalLimitsForAdmins to 1"
write-output "Setting BypassRecalLimitsForAdmins to 1" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
set-itemproperty -path "HKLM:\SOFTWARE\KVS\Enterprise Vault\FSA\PlaceholderService" -name "BypassRecalLimitsForAdmins" -value 1
$restart = 1
}
Else{
write-host "Not setting BypassRecalLimitsForAdmins can cause recall processing to fail if recall limits are encountered. Will exit. "
Break
}
}

If ($testreg.RecallLimitMaxRecalls -eq 99){
write-host "RecallLimitMaxrecalls is set to the highest accepted value (99) "
write-output "RecallLimitMaxrecalls is set to the highest accepted value (99) " >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
}
Else{
#write-host "RecallLimitMaxrecalls is NOT set to the highest accepted value (99) "
write-output "RecallLimitMaxrecalls is NOT set to the highest accepted value (99) " >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
$recalllimitnotset =$(read-host "The registry setting, RecallLimitMaxrecalls is not set to the highest acceptable value, would you like to set it? Use the format y or n ")

If ($recalllimitnotset -eq 'y'){
write-host "Setting RecallLimitMaxrecalls to 99"
write-output "Setting RecallLimitMaxrecalls to 99" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
set-itemproperty -path "HKLM:\SOFTWARE\KVS\Enterprise Vault\FSA\PlaceholderService" -name "RecallLimitMaxrecalls" -value 99
$restart = 1
}
Else{
write-host "Not setting RecallLimitMaxrecalls can cause recall processing to fail if recall limits are encountered. Will exit. "
Break
}
}

If ($testreg.RecallLimitTimeInterval -eq 1){
write-host "RecallLimitTimeInterval is set to the lowest accepted value (1) "
write-output "RecallLimitTimeInterval is set to the lowest accepted value (1) " >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
}
Else{
$recalllimitTnotset =$(read-host "The registry setting, RecallLimitTimeInterval is not set to the lowest acceptable value, would you like to set it? Use the format y or n ")

If ($recalllimitTnotset -eq 'y'){
write-host "Setting RecallLimitTimeInterval to 1"
write-output "Setting RecallLimitTimeInterval to 1" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
set-itemproperty -path "HKLM:\SOFTWARE\KVS\Enterprise Vault\FSA\PlaceholderService" -name "RecallLimitTimeInterval" -value 1
$restart = 1
}
Else{
write-host "Not setting RecallLimitTimeInterval can cause recall processing to fail if recall limits are encountered. Will exit. "
Break
}
}
}
Else{
write-output "Registry Read failed for path HKLM:\SOFTWARE\Wow6432Node\KVS\Enterprise Vault\FSA\PlaceholderService and HKLM:\SOFTWARE\KVS\Enterprise Vault\FSA\PlaceholderService Copy operations may be limited by recall limits "
}
}
Else{
write-host "Copy not selected "
write-output "Copy not selected " >> $exepath\test1.txt
}

if ($restart -gt 0){
restart-service "Enterprise Vault File Placeholder Service"
write-host "Restarting EV File Placeholder Service"
write-output "Restarting EV File Placeholder Service" >> $exepath\test1.txt
write-output "" >> $exepath\test1.txt
}

## ver.bat & $exepath"\batch.cmd" $tarpath > $exepath"\dirout.txt"

## & $exepath"\batch.cmd" $tarpath > $exepath"\dirout.txt"
## above worked at the command line in PS

## ver.bat $readlines = get-content $exepath\dirout.txt
##$readlines = get-childitem $tarpath -force -recurse where-object {$_.mode -notlike "d*"}

## ------------------------------------------------
## Edited by Me (u know)
## ------------------------------------------------

Get-Content $txtfile Foreach-Object {
$searchstring = $_
$searchbase = "$tarpath\$searchstring*"

write-host $searchbase
write-output "Searching folder beginning with $searchstring ..." >> "$exepath\$searchstring.txt"

## $readlines = get-childitem $searchbase -force -recurse where-object {$_.mode -notlike "d*" -and $_.length -lt 10000}

$readlines = get-childitem $searchbase -force -recurse -exclude *.ldb where-object {$_.mode -notlike "d*"}
#$readlines = get-childitem -LiteralPath "F:\Groups\Development\Developments - Commercial\Administration Stationary\VIC\GeneralAdmin\Expenses_04_05\051209memo[Expenses-Richard].doc"


## ------------------------------------------------

##
##
## $count = 0
foreach($readline in $readlines){
$fullname = $readline.fullname
$fsutilout = fsutil reparsepoint query "$fullname"
## pass fsutilout to new variable to ensure string
$fsutiloutst = "$fsutilout"
## debug ## write-host "running fsutil on file " $fullname " returned " $fsutiloutst

$filetest = Get-ChildItem -LiteralPath "$fullname" -Force

#trap{
# $filetest = Get-ChildItem -LiteralPath "$fullname" -Force
# "ERROR Filetest: file $filetest :: "+ $_ out-file "$exepath\$searchstring error.txt" -append
# write-host $_
# continue
#}

#$filetest = $fullname

$offline = $filetest.Attributes -band [System.IO.FileAttributes]::Offline

trap{
"ERROR->file $filetest :: "+ $_ out-file "$exepath\$searchstring error.txt" -append
write-host $_
continue
}

###$fatrout = & $exepath"\fatr.exe" -r "$fullname"
## next pass $fatrout to another variable to properly get it in a string
###$fatroutst = "$fatrout"
## debug ## write-host "running fatr in report mode on file " $fullname " returned " $fatroutst

## Logic for evaluation of the strings

## new test for offline - Determining if an attribute is set
## $File = Get-ChildItem .\test.txt -Force
## $File.Attributes
## if ( $File.Attributes -band [System.IO.FileAttributes]::Hidden )
## { Write-Host "Hidden Attribute Set" }

## Setting an attribute

## $File = Get-ChildItem .\test.txt -Force
## $File.Attributes
## $File.Attributes = ( $File.Attributes -bor [System.IO.FileAttributes]::System )
## $File.Attributes

## Removing an attribute
## $File = Get-ChildItem .\test.txt -Force
## $File.Attributes
## $File.Attributes = ( $File.Attributes -bxor [System.IO.FileAttributes]::System )
## $File.Attributes


If ($fsutiloutst -match'(?m:^Error)' -and $offline -eq 0){
$out1 = "The file "+$fullname+" has no EV reparse information and does not have the offline bit set, no action needed"
out-file -filepath "$exepath\$searchstring.txt" -inputobject $out1 -append

}
elseif ($fsutiloutst -replace ' ', '' -match '(^ReparseTagValue:0x00000010GUID:{9DD58ACD-4BE7-4F36-9CE3-B7738EE3C702})' -and $offline -eq 0){
$out2 = "The file "+$fullname+" has EV reparse information and does not have the offline bit set, will set offline bit"
out-file -filepath "$exepath\$searchstring.txt" -inputobject $out2 -append
$filetest.Attributes = $filetest.Attributes -bor [System.IO.FileAttributes]::Offline
# & $exepath"\fatr.exe" $fullname >> $exepath\test1.txt
}
elseif ($fsutiloutst -match'(?m:^Error)' -and $offline -eq 4096){
$out3 = "The file "+$fullname+" has no EV reparse information and does have the offline bit set, will clear offline bit"
out-file -filepath "$exepath\$searchstring.txt" -inputobject $out3 -append
$filetest.Attributes = $filetest.Attributes -bxor [System.IO.FileAttributes]::Offline
# & $exepath"\fatr.exe" $fullname >> $exepath\test1.txt
}
else{
## only case left should be has reparse, and has offline bit set
# $fullname
If ($copyquestion -match 'y'){
$out4 = "The file "+$fullname+" has EV reparse information, and is offline, will attempt to copy to nul device as copy selection set to 'y'"
out-file -filepath "$exepath\$searchstring.txt" -inputobject $out4 -append

#trap{
# "The File: "+ $fullname out-file "$exepath\$searchstring error.txt" -append
# "ERROR: "+ $_ out-file "$exepath\$searchstring error.txt" -append
# write-host $_
# continue
#}

## copy-item $fullname \\.\nul\ -verbose -force out-file -file path $exepath\test1.txt -append
copy-item -LiteralPath $fullname \\.\nul\
$copyresult = $?

write-output "Copy of $fullname to nul returned $copyresult " >> "$exepath\$searchstring.txt"
}
Else{
$out5 = "The file "+$fullname+" has EV reparse information, and is offline, will not attempt to copy to nul device as copy selection not set to 'y'"
out-file -filepath "$exepath\$searchstring.txt" -inputobject $out5 -append

## copy functionality ## write-host "file " $fullname " has reparse information and is offline, will attempt to copy to nul device"
##
## copy $fullname \\.\nul\
}
}
}


## ------------------------------------------------
## Edited by Me (u know)
## ------------------------------------------------
}
## ------------------------------------------------

Write-Output "" >> $exepath\test1.txt
Write-Output "Processing Completed" >> $exepath\test1.txt
get-date out-file -filepath $exepath\test1.txt -append

2 comments:

Albert Widjaja said...
This comment has been removed by the author.
Albert Widjaja said...

Hi Laurence,

Thanks for sharing the script, so what is "fatr.exe executable" ?

where can I find that file from ?