Skip to content

Commit

Permalink
Restore-CohesityRemoteMSSQLObject-Wrapper.ps1 is newly to Restore the…
Browse files Browse the repository at this point in the history
… DB (#178)

* Restore-CohesityRemoteMSSQLObject-Wrapper.ps1 is newly to Restore the DB
based on SqlHost, SqlObjectName and TargetHost.

Restore-CohesityRemoteMSSQLObject.ps1 : DbRestoreOverwritePolicy option
is newly added

* Updated markdown file for MSSQL remote restore.

* Included switch parameter to return result as object.

---------

Co-authored-by: KavishreeShanmugam11 <kshanmugam.maplelabs@cohesity.com>
  • Loading branch information
venmuthu and KavishreeShanmugam11 committed Jan 8, 2024
1 parent 257367e commit 3fc7496
Show file tree
Hide file tree
Showing 7 changed files with 330 additions and 41 deletions.
67 changes: 64 additions & 3 deletions docs/cmdlets-reference/restore-cohesityremotemssqlobject.md
Expand Up @@ -23,6 +23,15 @@ Restore-CohesityRemoteMSSQLObject [-TaskName <String>] -SourceId <Int64> -HostSo
[-DbRestoreOverwritePolicy] [-TargetHostId <Int64>] [-WhatIf] [-Confirm] [<CommonParameters>]
```

### SQL Host
```
Restore-CohesityRemoteMSSQLObject [-TaskName <String>] [-SqlHost <String>] [-SqlObjectName <String>] [-JobId <Int64>]
[-CaptureTailLogs] [-KeepCDC] [-NewDatabaseName <String>] [-NewInstanceName <String>]
[-RestoreTimeSecs <Int64>] [-TargetDataFilesDirectory <String>] [-TargetLogFilesDirectory <String>]
[-TargetSecondaryDataFilesDirectoryList <Object[]>] [-DbRestoreOverwritePolicy] [-TargetHost <String>]
[-WhatIf] [-Confirm] [<CommonParameters>]
```

## DESCRIPTION
From remote cluster restores the specified MS SQL object from a previous backup.

Expand All @@ -33,7 +42,7 @@ From remote cluster restores the specified MS SQL object from a previous backup.
Restore-CohesityRemoteMSSQLObject -SourceId 1279 -HostSourceId 1277 -JobId 31520 -TargetHostId 770 -CaptureTailLogs:$false -NewDatabaseName CohesityDB_r1 -NewInstanceName MSSQLSERVER -TargetDataFilesDirectory "C:\temp" -TargetLogFilesDirectory "C:\temp" -DbRestoreOverwritePolicy:$true
```

Restore MSSQL database from remote cluster with database id 1279 , database instance id 1277 and job id as 31520
Restore MSSQL database from remote cluster with database id 1279 , database instance id 1277 and job id as 31520 with the latest recoverable snapshot information.
$mssqlObjects = Find-CohesityObjectsForRestore -Environments KSQL
Get the source id, $mssqlObjects\[0\].SnapshottedSource.Id
Get the source instance id, $mssqlObjects\[0\].SnapshottedSource.SqlProtectionSource.OwnerId
Expand All @@ -58,6 +67,13 @@ $pattern2 = @{filePattern = "*.ldf"; targetDirectory = "c:\test1"}
$patternList += $pattern1
$patternList += $pattern2

### EXAMPLE 4
```
Restore-CohesityRemoteMSSQLObject -SqlHost x.x.x.x -JobId 31520 -SqlObjectName instance/databse_1 -TargetHost y.y.y.y -CaptureTailLogs:$false -NewDatabaseName CohesityDB_r1 -NewInstanceName MSSQLSERVER -TargetDataFilesDirectory "C:\temp" -TargetLogFilesDirectory "C:\temp" -DbRestoreOverwritePolicy:$true
```

Restore MSSQL database from remote cluster with database name database_1 from the sql host x.x.x.x, and job id as 31520 to the target host y.y.y.y with latest recoverable snapshot information.

## PARAMETERS

### -TaskName
Expand All @@ -84,7 +100,7 @@ Type: Int64
Parameter Sets: (All)
Aliases:

Required: True
Required: False
Position: Named
Default value: 0
Accept pipeline input: False
Expand All @@ -99,7 +115,7 @@ Type: Int64
Parameter Sets: (All)
Aliases:

Required: True
Required: False
Position: Named
Default value: 0
Accept pipeline input: False
Expand Down Expand Up @@ -217,6 +233,51 @@ Accept pipeline input: False
Accept wildcard characters: False
```

### -SqlHost
Specifies the SQL host from which database need to be restored.

```yaml
Type: String
Parameter Sets: (All)
Aliases:

Required: False
Position: Named
Default value: 0
Accept pipeline input: False
Accept wildcard characters: False
```

### -SqlObjectName
Specifies the name of the SQL Object to be restored.

```yaml
Type: String
Parameter Sets: (All)
Aliases:

Required: False
Position: Named
Default value: 0
Accept pipeline input: False
Accept wildcard characters: False
```

### -TargetHost
Specifies the target host if the application is to be restored to a different host.

```yaml
Type: String
Parameter Sets: (All)
Aliases:

Required: False
Position: Named
Default value: 0
Accept pipeline input: False
Accept wildcard characters: False
```

### -RestoreTimeSecs
Specifies the time in the past to which the SQL database needs to be restored.
This allows for granular recovery of SQL databases.
Expand Down
148 changes: 148 additions & 0 deletions samples/RestoreSQLDB/Restore-CohesityRemoteMSSQLObject-Wrapper.ps1
@@ -0,0 +1,148 @@
<#
Use the generic cmdlet to create an MSSQL remote restore task
Example usage:
Restore-CohesityRemoteMSSQLObject-Wrapper.ps1 -JobId 1234 -SqlHost x.x.x.x -SqlObjectName "MSSQLSERVER/database" -TargetHost y.y.y.y -CaptureTailLogs:$false -NewDatabaseName database_new -NewInstanceName SQL2016 -TargetDataFilesDirectory "C:\" -TargetLogFilesDirectory "C:\temp" -DbRestoreOverwritePolicy:$true
#>
[CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess = $True, ConfirmImpact = "High")]
Param(
[Parameter(Mandatory = $false)][switch]$CaptureTailLogs, # Specifies if the tail logs are to be captured before the restore operation. This is only applicable if restoring the SQL database to its hosting Protection Source and the database is not being renamed.
[Parameter(Mandatory = $false)][switch]$DbRestoreOverwritePolicy, # This field will overwrite the existing db contents if it sets to true. By default the db overwrite policy is false.
[Parameter(Mandatory = $true)][ValidateRange(1, [long]::MaxValue)][long]$JobId, # Specifies the job id that backed up this MS SQL instance and will be used for this restore
[Parameter(Mandatory = $false)][switch]$KeepCDC, # This field prevents "change data capture" settings from being reomved. When a database or log backup is restored on another server and database is recovered.
[Parameter(Mandatory = $false)][string]$NewDatabaseName, # Specifies a new name for the restored database.
[Parameter(Mandatory = $false)][string]$NewInstanceName, # Specifies the instance name of the SQL Server that should be restored.
[Parameter(Mandatory = $false)][long]$RestoreTimeSecs = 0, # Specifies the time in the past to which the SQL database needs to be restored. This allows for granular recovery of SQL databases. If not specified, the SQL database will be restored from the full/incremental snapshot.
[Parameter(Mandatory = $true)][string]$SqlHost, # Specifies the SQL Host information
[Parameter(Mandatory = $true)][string]$SqlObjectName, # Specifies the SQL Object Name
[Parameter(Mandatory = $false)][string]$TargetDataFilesDirectory, # Specifies the directory where to put the database data files. Missing directory will be automatically created. This field must be set if restoring to a different target host.
[Parameter(Mandatory = $true)][string]$TargetHost, # Specifies the target host to restore
[Parameter(Mandatory = $false)][string]$TargetLogFilesDirectory, # Specifies the directory where to put the database log files. Missing directory will be automatically created. This field must be set if restoring to a different target host.
[Parameter(Mandatory = $false)][Object[]]$TargetSecondaryDataFilesDirectoryList # Specifies the secondary data filename pattern and corresponding directories of the DB. Secondary data files are optional and are user defined. The recommended file extension for secondary files is ".ndf". If this option is specified and the destination folders do not exist they will be automatically created. This field can be set only if restoring to a different target host.
)

# Check if specified job exists
$job = Get-CohesityProtectionJob -Ids $JobId
if (-not $job) {
Write-Output "Cannot proceed, the job id '$JobId' is invalid"
return
}

$HostSourceId
$JobRunId
$SourceId = 0
$StartTime
$TargetHostId = 0

# Get the list of SQL objects that can be restored and fetch the id of the specified SQL host
$sqlRecords = Find-CohesityObjectsForRestore -Environments KSQL -JobIds $JobId | Where-Object { $_.ObjectName -eq $SqlObjectName }

$searchedVMDetails = $null
$searchIndex = 0
$continuePagination = $true
$searchTotalCount = 0

# Loop through the result to fetch the specified SQL host id and parent id
foreach ($record in $sqlRecords) {
while ($continuePagination) {
$searchURL = '/irisservices/api/v1/searchvms?from=' + $searchIndex + '&environment=SQL&entityTypes=kSQL&showAll=false&onlyLatestVersion=true&jobIds=' + $JobId
$searchVMResult = Invoke-RestApi -Method Get -Uri $searchURL

if ($Global:CohesityAPIStatus.StatusCode -ne 200) {
Write-Output "Could not search MSSQL objects associated with the job id $JobId"
return
}

$vmList = $searchVMResult.vms
foreach ($vm in $vmList) {
if ($vm.vmDocument.objectAliases[0] -eq $SqlHost) {
$SourceId = $record.SnapshottedSource.Id
$HostSourceId = $record.SnapshottedSource.ParentId
break
}
}

$searchedVMDetails = $searchVMResult.vms | Where-Object { ($_.vmDocument.objectId.jobId -eq $JobId) -and ($_.vmDocument.objectId.entity.id -eq $SourceId) }

if ($searchTotalCount -eq 0) {
# find the expected number of search result items
$searchTotalCount = $searchVMResult.count
}

if ($searchedVMDetails) {
$infoMsg = "Found database with search index " + $searchIndex + ", and total item count " + $searchTotalCount
CSLog -Message $infoMsg
$continuePagination = $false
}

# the number of items skimmed
$searchIndex += $searchVMResult.vms.Count

if ($searchIndex -ge $searchTotalCount) {
$continuePagination = $false
}
if ($continuePagination -eq $false) {
break
}
}
if ($null -eq $searchedVMDetails) {
Write-Output "Could not find details of MSSQL host '$SqlHost'."
return
}
}

if ($SourceId -eq 0) {
Write-Output "Cannot proceed, Unable to find source id for SQL host '$SqlHost'"
return
}

# Fin dthe Id of specified target host
$protectionSources = Get-CohesityProtectionSource -Environments KSQL
foreach ($record in $protectionSources) {
if ($record.protectionSource.Name -eq $TargetHost) {
$TargetHostId = $record.protectionSource.id
}
}

if ($TargetHostId -eq 0) {
Write-Output "Unable to find host if for $TargetHost"
return
}

# Identifying the JobRunId and StartTime based on the last known unexpired snapshot
# here the curent system time should be less than the recent successful snapshot expiry time
$runs = Get-CohesityProtectionJobRun -JobId $JobId -ExcludeErrorRuns:$true
foreach ($record in $runs) {

$expiryEpocTime = $record.copyRun[0].expiryTimeUsecs
$currentTime = Get-Date
$currentEpocTime = Get-Date $currentTime -UFormat %s
if ($currentEpocTime -le $expiryEpocTime) {

$JobRunId = $record[0].backupRun.jobRunId
$StartTime = $record.copyRun[0].runStartTimeUsecs
break
}
}

$sqlRestoreParams = @{
JobID = $JobId
SourceID = $SourceId
HostSourceID = $HostSourceId
TargetHostID = $TargetHostId
JobRunId = $JobRunId
StartTime = $StartTime
CaptureTailLogs = $CaptureTailLogs.IsPresent
KeepCDC = $KeepCDC.isPresent
NewDatabaseName = $NewDatabaseName
NewInstanceName = $NewInstanceName
Verbose = $true
Confirm = $false
TargetDataFilesDirectory = $TargetDataFilesDirectory
TargetLogFilesDirectory = $TargetLogFilesDirectory
TargetSecondaryDataFilesDirectoryList = $TargetSecondaryDataFilesDirectoryList
RestoreTimeSecs = $RestoreTimeSecs
DbRestoreOverwritePolicy = $DbRestoreOverwritePolicy
}

Restore-CohesityRemoteMSSQLObject @sqlRestoreParams
6 changes: 3 additions & 3 deletions src/Cohesity.Powershell/Cohesity.PowerShell.Core.psd1
Expand Up @@ -8,7 +8,7 @@
RootModule = 'Cohesity.PowerShell.Core.dll'

# Version number of this module.
ModuleVersion = '1.9.5'
ModuleVersion = '1.9.6'

# Supported PSEditions
# CompatiblePSEditions = @()
Expand Down Expand Up @@ -76,7 +76,7 @@ FunctionsToExport = @(
'Copy-CohesityView',
'Copy-CohesityVMwareVM',
'Find-CohesityFileSnapshot',
'Find-CohesityRemoteRestFileSnapshot',
'Find-CohesityRemoteFileSnapshot',
'Get-CohesityActiveDirectory',
'Get-CohesityCmdletConfig',
'Get-CohesityExternalClient',
Expand Down Expand Up @@ -132,7 +132,7 @@ FunctionsToExport = @(
'Remove-CohesityVirtualIP',
'Remove-CohesityVlan',
'Restore-CohesityBackupToView',
'Restore-CohesityFileV2'
'Restore-CohesityFileV2',
'Restore-CohesityRemoteFile',
'Restore-CohesityRemoteFileV2',
'Restore-CohesityOracleDatabase',
Expand Down
2 changes: 1 addition & 1 deletion src/Cohesity.Powershell/Cohesity.PowerShell.psd1
Expand Up @@ -8,7 +8,7 @@
RootModule = 'Cohesity.PowerShell.dll'

# Version number of this module.
ModuleVersion = '1.9.5'
ModuleVersion = '1.9.6'

# Supported PSEditions
# CompatiblePSEditions = @()
Expand Down
Expand Up @@ -54,6 +54,10 @@ function Get-CohesityProtectionJobStatus {
#>
[CmdletBinding()]
Param(
[Parameter(
Position = 1,
HelpMessage = "Return Output as Object")]
[Switch]$ReturnObject
)

Begin {
Expand Down Expand Up @@ -146,13 +150,18 @@ function Get-CohesityProtectionJobStatus {
}

$columnWidth = 20
$protectionJobStatusList | Sort-Object -Property startTime -Descending |
Format-Table @{ Label = 'ID'; Expression = { $_.jobId }; },
@{ Label = 'NAME'; Expression = { $_.jobName }; Width = $columnWidth; },
@{ Label = 'REMOTE COPY'; Expression = { $_.remoteCopy }; Width = $columnWidth },
@{ Label = 'STARTED AT'; Expression = { $_.GetStartTime() }; Width = $columnWidth },
@{ Label = 'ESTIMATED TIME'; Expression = { $_.GetEstimatedTime() }; Width = $columnWidth },
@{ Label = 'COMPLETED(%)'; Expression = { $_.percentCompleted }; Width = $columnWidth }
if ($ReturnObject -eq $true) {
return $protectionJobStatusList
}
else {
$protectionJobStatusList | Sort-Object -Property startTime -Descending |
Format-Table @{ Label = 'ID'; Expression = { $_.jobId }; },
@{ Label = 'NAME'; Expression = { $_.jobName }; Width = $columnWidth; },
@{ Label = 'REMOTE COPY'; Expression = { $_.remoteCopy }; Width = $columnWidth },
@{ Label = 'STARTED AT'; Expression = { $_.GetStartTime() }; Width = $columnWidth },
@{ Label = 'ESTIMATED TIME'; Expression = { $_.GetEstimatedTime() }; Width = $columnWidth },
@{ Label = 'COMPLETED(%)'; Expression = { $_.percentCompleted }; Width = $columnWidth }
}
}

End {
Expand Down
@@ -1,5 +1,5 @@
function Register-CohesityProtectionSourceHyperV {
<#
<#
.SYNOPSIS
Registers a new HyperV protection source with the Cohesity Cluster. The HyperV type can be a SCVMM server or HyperV Host.
.DESCRIPTION
Expand Down Expand Up @@ -29,15 +29,18 @@ function Register-CohesityProtectionSourceHyperV {
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
# User credentials for the SCVMM server.
[System.Management.Automation.PSCredential]$Credentials
[System.Management.Automation.PSCredential]$Credentials,
# Set to true, if result need to returned in object format
[Parameter(Position = 1, HelpMessage = "Return Output as Object", Mandatory = $false)]
[Switch]$ReturnObject
)

Begin {
}

Process {

$uri = '/irisservices/api/v1/public/protectionSources/register'
$uri = '/irisservices/api/v1/public/protectionSources/register'

if ($HyperVType -eq 'KSCVMMServer') {
$reqParameters = @{
Expand All @@ -58,10 +61,16 @@ function Register-CohesityProtectionSourceHyperV {

$columnWidth = 20
$request = $reqParameters | ConvertTo-Json
Invoke-RestApi -Method Post -Uri $uri -Body $request |
Format-Table @{ Label = 'ID'; Expression = { $_.id }; },
@{ Label = 'Name'; Expression = { $_.name }; Width = $columnWidth; },
@{ Label = 'Environment'; Expression = { $_.environment }; Width = $columnWidth },
@{ Label = 'Type'; Expression = { $_.hypervProtectionSource.type }; Width = $columnWidth }
$result = Invoke-RestApi -Method Post -Uri $uri -Body $request

if ($ReturnObject -eq $true) {
return $result
}
else {
$result | Format-Table @{ Label = 'ID'; Expression = { $_.id }; },
@{ Label = 'Name'; Expression = { $_.name }; Width = $columnWidth; },
@{ Label = 'Environment'; Expression = { $_.environment }; Width = $columnWidth },
@{ Label = 'Type'; Expression = { $_.hypervProtectionSource.type }; Width = $columnWidth }
}
} # End of process
} # End of function

0 comments on commit 3fc7496

Please sign in to comment.