ES1_ArchiveFolder.psm1
<# .NOTES =========================================================================== Copyright � 2018 Dell Inc. or its subsidiaries. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 =========================================================================== THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. IF THIS CODE AND INFORMATION IS MODIFIED, THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE AND INFORMATION REMAINS WITH THE USER. .DESCRIPTION Functions and objects for creating S1 Archive (backend) Folders #> function New-ES1ArchiveFolderOptions { <# .SYNOPSIS Returns a helper object containing many default Archive folder options .DESCRIPTION Returns a helper object containing many default Archive folder options. The helper wraps the [EMC.Interop.ExAsAdminAPI.exASObjectType]::exASObjectType_ArchiveFolder object. The default options can be modified/changed by changing the values in the folderdefaults.xml located in the modules' directory .OUTPUTS .EXAMPLE $newfolder = New-ES1ArchiveFolderOptions -ArchiveName 'MyArchive' -FolderName '2Year' -ContainerLocation '\\S1MASTER7-J1\PBA' -IndexLocation '\\S1MASTER7-J1\IndexShare' #> [OutputType('EMC.Interop.ExAsAdminAPI.exASObjectType.exASObjectType_ArchiveFolder')] [CmdletBinding()] PARAM( [Parameter(Mandatory=$true)] [Alias('archive')] [string] $ArchiveName, [Parameter(Mandatory=$true)] [Alias('name')] [string] $FolderName, [Parameter(Mandatory=$false)] [Alias('container')] [string] $ContainerLocation, [Parameter(Mandatory=$false)] [Alias('index')] [string] $IndexLocation ) BEGIN{ $MyDebug = $false # Do both these checks to take advantage of internal parsing of syntaxes like -Debug:$false if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Debug") -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" Write-Debug "Debug Output activated" # for convenience $MyDebug = $true } try { [bool] $loaded = Add-ES1Types #-ErrorAction SilentlyContinue if (-not $loaded ) { Write-Error 'Error loading SourceOne Objects and Types' break } } catch { Write-Error $_ break } } PROCESS { # get script location, load defaults from it... $scriptDirectory = Split-Path -parent $PSCommandPath $folderDefaults = join-path $scriptDirectory 'folderdefaults.xml' try { # Make sure the input file exists... if (!(Test-Path -path $folderDefaults) ) { throw "Folder default settings file not found: $folderDefaults" } # TODO - Optimize loading this only once, instead of every time called - Jay R. # Load the common/general folder defaults. [System.Xml.XmlDocument] $settingsxml = new-object System.Xml.XmlDocument $settingsxml.load($folderDefaults) $GeneralSettings = $settingsxml.SelectSingleNode('/ES1FolderDefaults/ArchiveFolder/General') $asmgr = new-object -ComObject ExAsAdminAPI.CoExASAdminAPI $asmgr.Initialize() $repo = $asmgr.GetRepository($ArchiveName) $backendFolder = $repo.CreateNewObject([EMC.Interop.ExAsAdminAPI.exASObjectType]::exASObjectType_ArchiveFolder) $backendFolder.SetTraceInfo($Global:S1LogFile) $backendFolder.FullPath = $FolderName $backendFolder.ContainerLocation = $ContainerLocation $backendFolder.IndexLocation = $IndexLocation $backendFolder.ContentCache = [System.Convert]::ToBoolean($GeneralSettings.ContentCache) $backendFolder.MaxIndexSize = [System.Convert]::ToInt32($GeneralSettings.MaxIndexSize) $backendFolder.FullTextEnabled = [System.Convert]::ToBoolean($GeneralSettings.FullTextEnabled) $backendFolder.MaxVolumeSize = [System.Convert]::ToInt32($GeneralSettings.MaxVolumeSize) $backendFolder.AttachmentIndexing = [System.Convert]::ToInt32($GeneralSettings.AttachmentIndexing) ## NOTE : 0 = enabled # Store content inside containers, set this to a size in KB for large content outside containers. $backendFolder.AttachmentSizeThreshold=-2 # release the repo object [System.Runtime.Interopservices.Marshal]::ReleaseComObject($repo) > $null $backendFolder } catch{ Write-Error $_ throw $_ } } END {} } function New-ES1NASArchiveFolder { <# .SYNOPSIS Creates a new "NAS Container" type of archive folder. Note: Parameter validation may not be identical to the SourceOne Administration GUI. .DESCRIPTION Creates a new "NAS Container" type of archive folder Note: Parameter validation may not be identical to the SourceOne Administration GUI. .OUTPUTS .EXAMPLE New-ES1NASArchiveFolder -Archivename Archive1 -FolderName 'NewFolder' -ContainerLocation '\\S1MASTER7-J1\xxx' -IndexLocation '\\S1MASTER7-J1\IndexShare' #> [CmdletBinding()] PARAM( [Parameter(Mandatory=$true)] [Alias('archive')] [string] $ArchiveName, [Parameter(Mandatory=$false)] [Alias('name')] [string] $FolderName, [Parameter(Mandatory=$false)] [Alias('container')] [string] $ContainerLocation, [Parameter(Mandatory=$false)] [Alias('index')] [string] $IndexLocation ) BEGIN{ $MyDebug = $false # Do both these checks to take advantage of internal parsing of syntaxes like -Debug:$false if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Debug") -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" Write-Debug "Debug Output activated" # for convenience $MyDebug = $true } try { [bool] $loaded = Add-ES1Types #-ErrorAction SilentlyContinue if (-not $loaded ) { Write-Error 'Error loading SourceOne Objects and Types' break } } catch { Write-Error $_ break } } PROCESS { try { $newfolder = New-ES1ArchiveFolderOptions -ArchiveName $ArchiveName -FolderName $FolderName -ContainerLocation $ContainerLocation -IndexLocation $IndexLocation $newfolder.StorageType = [EMC.Interop.ExASBaseAPI.exASFolderStorageType]::exASStorageType_NASContainer try{ $validation = $newfolder.Validate() foreach ($result in $validation) { if ($result.IsWarning ) { Write-Warning "$($result.errorDescription)" } else { throw "$($result.errorDescription)" } } $newfolder.Save() } catch { throw $_ } finally{ [System.Runtime.Interopservices.Marshal]::ReleaseComObject($newfolder) > $null } } catch { Write-Error $_ } } END {} } function New-ES1CenteraArchiveFolder { <# .SYNOPSIS Creates a new "Centera Container" type of archive folder. Note: Parameter validation may not be identical to the SourceOne Administration GUI. .DESCRIPTION Creates a new "Centera Container" type of archive folder Note: Parameter validation may not be identical to the SourceOne Administration GUI. .EXAMPLE New-ES1CenteraArchiveFolder -Archivename Archive1 -FolderName 'Cent1' -pool '168.159.214.11' -IndexLocation '\\S1MASTER7-J1\IndexShare' .EXAMPLE New-ES1CenteraArchiveFolder -Archivename Archive1 -FolderName 'Cent2' -pool '168.159.214.20;168.159.214.21;168.159.214.22' -CenteraPEAFile 'C:\temp\c2profile3.pea' -IndexLocation '\\S1MASTER7-J1\IndexShare' #> [CmdletBinding()] PARAM( [Parameter(Mandatory=$true)] [Alias('archive')] [string] $ArchiveName, [Parameter(Mandatory=$false)] [Alias('name')] [string] $FolderName, [Parameter(Mandatory=$true)] [Alias('pool')] [string] $CenteraPool, [Parameter(Mandatory=$false)] [Alias('pea')] [string] $CenteraPEAFile, [Parameter(Mandatory=$false)] [Alias('index')] [string] $IndexLocation ) BEGIN{ $MyDebug = $false # Do both these checks to take advantage of internal parsing of syntaxes like -Debug:$false if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Debug") -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" Write-Debug "Debug Output activated" # for convenience $MyDebug = $true } try { [bool] $loaded = Add-ES1Types #-ErrorAction SilentlyContinue if (-not $loaded ) { Write-Error 'Error loading SourceOne Objects and Types' break } } catch { Write-Error $_ break } } PROCESS { $ContainerLocation='' $peaString='' try { if ($CenteraPEAFile.Length -gt 0) { # Make sure the input file exists... if (!(Test-Path -path $CenteraPEAFile) ) { throw "PEA file not found!: $CenteraPEAFile" } # Load the PEA file if one was given $peaString= Get-Content $CenteraPEAFile } # Get a new folder options object with many defaults already set $newfolder = New-ES1ArchiveFolderOptions -ArchiveName $ArchiveName -FolderName $FolderName -ContainerLocation $ContainerLocation ` -IndexLocation $IndexLocation # Set the storage container type $newfolder.StorageType = [EMC.Interop.ExASBaseAPI.exASFolderStorageType]::exASStorageType_CenteraContainer $newfolder.CenteraPoolAddress=$CenteraPool if ($peaString.Length -gt 0) { $newfolder.CenteraPEAConfigString =$peaString } try{ # Check the Centera connection info # This will throw if it fails. $newfolder.TestCenteraConnection($CenteraPool, $peaString) # Validate the rest of the settings $validation=$newfolder.Validate() foreach ($result in $validation) { if ($result.IsWarning ) { Write-Warning "$($result.errorDescription)" } else { throw "$($result.errorDescription)" } } # Everything is OK, Save it... $newfolder.Save() } catch { throw $_ } finally{ # Release this object cause we're done with it. [System.Runtime.Interopservices.Marshal]::ReleaseComObject($newfolder) > $null } } catch { Write-Error $_ } } END {} } function Show-ES1ArchiveFolders { <# .SYNOPSIS Displays all the properties of an Archive folder. .DESCRIPTION Displays all the properties of an Archive folder. .OUTPUTS .EXAMPLE Show-ES1ArchiveFolders #> [CmdletBinding()] PARAM( ) BEGIN{ $MyDebug = $false # Do both these checks to take advantage of internal parsing of syntaxes like -Debug:$false if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Debug") -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" Write-Debug "Debug Output activated" # for convenience $MyDebug = $true } try { [bool] $loaded = Add-ES1Types #-ErrorAction SilentlyContinue if (-not $loaded ) { Write-Error 'Error loading SourceOne Objects and Types' break } } catch { Write-Error $_ break } } PROCESS { try { $asmgr = new-object -ComObject ExAsAdminAPI.CoExASAdminAPI $asmgr.Initialize() $repos=$asmgr.EnumerateRepositories() foreach ($repo in $repos) { Write-Host "Archive Name: $($repo.Name)" Write-Host "" $folderplan=$repo.GetFolderPlan() $folders = $folderplan.EnumerateArchiveFolders() foreach ($folder in $folders) { Write-Host "Archive Folder: $($folder.FullPath)" Write-Host "Folder Properties" $folder | Format-List -Property * } [System.Runtime.Interopservices.Marshal]::ReleaseComObject($folderplan) > $null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($repo) > $null } } catch { throw $_ } finally { } } END{} } function Get-ES1ArchiveFolder { <# .SYNOPSIS Gets an instance of an existing Archive folder .DESCRIPTION Gets an instance of an existing Archive folder .EXAMPLE Get-ES1ArchiveFolder -ArchiveName Archive1 -FolderName 5Year #> [CmdletBinding()] PARAM( [Parameter(Mandatory=$true)] [Alias('archive')] [string] $ArchiveName, [Parameter(Mandatory=$false)] [Alias('name')] [string] $FolderName ) BEGIN{ $MyDebug = $false # Do both these checks to take advantage of internal parsing of syntaxes like -Debug:$false if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Debug") -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" Write-Debug "Debug Output activated" # for convenience $MyDebug = $true } try { [bool] $loaded = Add-ES1Types #-ErrorAction SilentlyContinue if (-not $loaded ) { Write-Error 'Error loading SourceOne Objects and Types' break } } catch { Write-Error $_ break } } PROCESS { try { Write-Verbose "Archive Name: $($ArchiveName), Archive Folder: $($FolderName)" $asmgr = new-object -ComObject ExAsAdminAPI.CoExASAdminAPI $asmgr.SetTraceInfo($Global:S1LogFile) $asmgr.Initialize() $repo=$asmgr.GetRepository($ArchiveName) $repo.SetTraceInfo($Global:S1LogFile) $folderplan=$repo.GetFolderPlan() $folders = $folderplan.EnumerateArchiveFolders() foreach ($folder in $folders) { if (($folder.Name -eq $FolderName) ) { $retFolder = $folder break; } } [System.Runtime.Interopservices.Marshal]::ReleaseComObject($folderplan) > $null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($repo) > $null } catch { Write-Error $_ } $retFolder } END {} } function Get-ES1AllArchiveFolders { <# .SYNOPSIS Gets a list all archive folders and their properties .DESCRIPTION Gets a list all archive folders and their properties .OUTPUTS .EXAMPLE $folders=Get-ES1AllArchiveFolders #> [CmdletBinding()] PARAM( ) BEGIN{ $MyDebug = $false # Do both these checks to take advantage of internal parsing of syntaxes like -Debug:$false if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Debug") -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" Write-Debug "Debug Output activated" # for convenience $MyDebug = $true } try { [bool] $loaded = Add-ES1Types #-ErrorAction SilentlyContinue if (-not $loaded ) { Write-Error 'Error loading SourceOne Objects and Types' break } } catch { Write-Error $_ break } } PROCESS { $allfolders=@() try { $asmgr = new-object -ComObject ExAsAdminAPI.CoExASAdminAPI $asmgr.Initialize() $repos=$asmgr.EnumerateRepositories() foreach ($repo in $repos) { $folderplan=$repo.GetFolderPlan() $folders = $folderplan.EnumerateArchiveFolders() $allfolders += $folders [System.Runtime.Interopservices.Marshal]::ReleaseComObject($folderplan) > $null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($repo) > $null } } catch { throw $_ } finally { } $allfolders } END{} } <# .SYNOPSIS Get a Archive folder summary information, similar to what is displayed in the MMC console .DESCRIPTION Get a Archive folder summary information, similar to what is displayed in the MMC console .OUTPUTS .EXAMPLE #> Function Get-ArchiveFolderSummaryInfo { [CmdletBinding()] PARAM () BEGIN{ $MyDebug = $false # Do both these checks to take advantage of internal parsing of syntaxes like -Debug:$false if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Debug") -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" Write-Debug "Debug Output activated" # for convenience $MyDebug = $true } try { [bool] $loaded = Add-ES1Types #-ErrorAction SilentlyContinue if (-not $loaded ) { Write-Error 'Error loading SourceOne Objects and Types' break } } catch { Write-Error $_ break } } PROCESS { $allfolders=@() try { $asmgr = new-object -ComObject ExAsAdminAPI.CoExASAdminAPI $asmgr.Initialize() $repos=$asmgr.EnumerateRepositories() foreach ($repo in $repos) { $folderplan=$repo.GetFolderPlan() $folders = $folderplan.EnumerateArchiveFolders() # change the properties to be like the MMC display $folderSummary = $folders | Select-Object Name, @{name="Volumes"; Expression = {$_.TotalVolumes}},` @{name="Volume Items"; Expression = {$_.TotalMsgInVolumes}},` @{name="Volume Size(MB)"; Expression = {$_.TotalSizeInVolumes}}, ` @{name="Indexes"; Expression = {$_.TotalIndexes}},` @{name="Index Items"; Expression = {$_.TotalMsgInIndexes}},` @{name="Index Size(MB)"; Expression = {$_.TotalSizeInIndexes}},` @{name="Errors"; Expression = {$_.FPErrorCount}} # put the archive name on each item, so consumers have context $folderSummary | Add-Member NoteProperty -Name "Archive" -Value $repo.Name $allfolders += $folderSummary [System.Runtime.Interopservices.Marshal]::ReleaseComObject($folderplan) > $null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($repo) > $null } } catch { throw $_ } finally { } $allfolders } END{} } <# .SYNOPSIS Get the monthly totals of an Archive folder, similar to what is displayed in the MMC console when the folder is expanded. .DESCRIPTION Get the monthly totals of an Archive folder, similar to what is displayed in the MMC console when the folder is expanded. .OUTPUTS .EXAMPLE #> Function Get-ArchiveFolderMonthlyInfo { [CmdletBinding()] PARAM ( [Parameter(Mandatory=$false)] [Alias('archive')] [string] $ArchiveName, [Parameter(Mandatory=$false)] [Alias('name')] [string] $FolderName) BEGIN { $MyDebug = $false # Do both these checks to take advantage of internal parsing of syntaxes like -Debug:$false if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey("Debug") -and $PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { $DebugPreference = "Continue" Write-Debug "Debug Output activated" # for convenience $MyDebug = $true } try { [bool] $loaded = Add-ES1Types #-ErrorAction SilentlyContinue if (-not $loaded ) { Write-Error 'Error loading SourceOne Objects and Types' break } } catch { Write-Error $_ break } } PROCESS { $asmgr = new-object -ComObject ExAsAdminAPI.CoExASAdminAPI $asmgr.Initialize() # If an archive was specified get only that one if ($ArchiveName) { $repos=@($asmgr.GetRepository($ArchiveName)) } else { # Get a list of ALL the repositories/archives $repos=$asmgr.EnumerateRepositories() } # Loop through the repositories/archives, getting the folders and months $MonthsSummary=@() foreach ($repo in $repos) { $repo.SetTraceInfo($Global:S1LogFile) $folderplan=$repo.GetFolderPlan() $folders = $folderplan.EnumerateArchiveFolders() foreach ($folder in $folders) { # If foldername is specified get only the info for that folder if ($FolderName -and ($folder.Name -ne $FolderName) ) { continue; } $containerfolders=@() $containerfolders=$folder.EnumerateContainerFolders() # change the properies to be like the MMC display $MonthsSummary += $containerfolders | Select-Object @{name="Archive"; Expression = {$repo.Name}}, ` @{name="Folder"; Expression = {$folder.Name}}, ` Name, ` @{name="Volumes"; Expression = {$_.TotalVolumes}},` @{name="Volume Items"; Expression = {$_.TotalMsgInVolumes}},` @{name="Volume Size(MB)"; Expression = {$_.TotalSizeInVolumes}}, ` @{name="Indexes"; Expression = {$_.TotalIndexes}},` @{name="Index Items"; Expression = {$_.TotalMsgInIndexes}},` @{name="Index Size(MB)"; Expression = {$_.TotalSizeInIndexes}},` @{name="Errors"; Expression = {$_.FPErrorCount}} } [System.Runtime.Interopservices.Marshal]::ReleaseComObject($folderplan) > $null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($repo) > $null } $MonthsSummary } END {} } New-Alias GetS1ArchiveFolder Get-ES1ArchiveFolder New-Alias Get-ArchiveFolderSummary Get-ArchiveFolderSummaryInfo Export-ModuleMember -Function * -Alias * |