diff --git a/docs/cmdlets-reference/restore-cohesityremotemssqlobject.md b/docs/cmdlets-reference/restore-cohesityremotemssqlobject.md index fa49443f..1ea796ec 100644 --- a/docs/cmdlets-reference/restore-cohesityremotemssqlobject.md +++ b/docs/cmdlets-reference/restore-cohesityremotemssqlobject.md @@ -23,6 +23,15 @@ Restore-CohesityRemoteMSSQLObject [-TaskName ] -SourceId -HostSo [-DbRestoreOverwritePolicy] [-TargetHostId ] [-WhatIf] [-Confirm] [] ``` +### SQL Host +``` +Restore-CohesityRemoteMSSQLObject [-TaskName ] [-SqlHost ] [-SqlObjectName ] [-JobId ] + [-CaptureTailLogs] [-KeepCDC] [-NewDatabaseName ] [-NewInstanceName ] + [-RestoreTimeSecs ] [-TargetDataFilesDirectory ] [-TargetLogFilesDirectory ] + [-TargetSecondaryDataFilesDirectoryList ] [-DbRestoreOverwritePolicy] [-TargetHost ] + [-WhatIf] [-Confirm] [] +``` + ## DESCRIPTION From remote cluster restores the specified MS SQL object from a previous backup. @@ -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 @@ -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 @@ -84,7 +100,7 @@ Type: Int64 Parameter Sets: (All) Aliases: -Required: True +Required: False Position: Named Default value: 0 Accept pipeline input: False @@ -99,7 +115,7 @@ Type: Int64 Parameter Sets: (All) Aliases: -Required: True +Required: False Position: Named Default value: 0 Accept pipeline input: False @@ -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. diff --git a/samples/RestoreSQLDB/Restore-CohesityRemoteMSSQLObject-Wrapper.ps1 b/samples/RestoreSQLDB/Restore-CohesityRemoteMSSQLObject-Wrapper.ps1 new file mode 100644 index 00000000..9d0769ed --- /dev/null +++ b/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 \ No newline at end of file diff --git a/src/Cohesity.Powershell/Cohesity.PowerShell.Core.psd1 b/src/Cohesity.Powershell/Cohesity.PowerShell.Core.psd1 index 09c67ef6..65c500f8 100644 --- a/src/Cohesity.Powershell/Cohesity.PowerShell.Core.psd1 +++ b/src/Cohesity.Powershell/Cohesity.PowerShell.Core.psd1 @@ -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 = @() @@ -76,7 +76,7 @@ FunctionsToExport = @( 'Copy-CohesityView', 'Copy-CohesityVMwareVM', 'Find-CohesityFileSnapshot', - 'Find-CohesityRemoteRestFileSnapshot', + 'Find-CohesityRemoteFileSnapshot', 'Get-CohesityActiveDirectory', 'Get-CohesityCmdletConfig', 'Get-CohesityExternalClient', @@ -132,7 +132,7 @@ FunctionsToExport = @( 'Remove-CohesityVirtualIP', 'Remove-CohesityVlan', 'Restore-CohesityBackupToView', - 'Restore-CohesityFileV2' + 'Restore-CohesityFileV2', 'Restore-CohesityRemoteFile', 'Restore-CohesityRemoteFileV2', 'Restore-CohesityOracleDatabase', diff --git a/src/Cohesity.Powershell/Cohesity.PowerShell.psd1 b/src/Cohesity.Powershell/Cohesity.PowerShell.psd1 index 1abbca8e..507d3a1c 100644 --- a/src/Cohesity.Powershell/Cohesity.PowerShell.psd1 +++ b/src/Cohesity.Powershell/Cohesity.PowerShell.psd1 @@ -8,7 +8,7 @@ RootModule = 'Cohesity.PowerShell.dll' # Version number of this module. -ModuleVersion = '1.9.5' +ModuleVersion = '1.9.6' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/src/Cohesity.Powershell/Scripts/ProtectionJob/Get-CohesityProtectionJobStatus.ps1 b/src/Cohesity.Powershell/Scripts/ProtectionJob/Get-CohesityProtectionJobStatus.ps1 index a23c0756..8270bf09 100644 --- a/src/Cohesity.Powershell/Scripts/ProtectionJob/Get-CohesityProtectionJobStatus.ps1 +++ b/src/Cohesity.Powershell/Scripts/ProtectionJob/Get-CohesityProtectionJobStatus.ps1 @@ -54,6 +54,10 @@ function Get-CohesityProtectionJobStatus { #> [CmdletBinding()] Param( + [Parameter( + Position = 1, + HelpMessage = "Return Output as Object")] + [Switch]$ReturnObject ) Begin { @@ -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 { diff --git a/src/Cohesity.Powershell/Scripts/ProtectionSource/Register-CohesityProtectionSourceHyperV.ps1 b/src/Cohesity.Powershell/Scripts/ProtectionSource/Register-CohesityProtectionSourceHyperV.ps1 index 6811441a..6064ce8e 100644 --- a/src/Cohesity.Powershell/Scripts/ProtectionSource/Register-CohesityProtectionSourceHyperV.ps1 +++ b/src/Cohesity.Powershell/Scripts/ProtectionSource/Register-CohesityProtectionSourceHyperV.ps1 @@ -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 @@ -29,7 +29,10 @@ 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 { @@ -37,7 +40,7 @@ function Register-CohesityProtectionSourceHyperV { Process { - $uri = '/irisservices/api/v1/public/protectionSources/register' + $uri = '/irisservices/api/v1/public/protectionSources/register' if ($HyperVType -eq 'KSCVMMServer') { $reqParameters = @{ @@ -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 \ No newline at end of file diff --git a/src/Cohesity.Powershell/Scripts/Restore/Restore-CohesityRemoteMSSQLObject.ps1 b/src/Cohesity.Powershell/Scripts/Restore/Restore-CohesityRemoteMSSQLObject.ps1 index 46fee544..16e18e3f 100644 --- a/src/Cohesity.Powershell/Scripts/Restore/Restore-CohesityRemoteMSSQLObject.ps1 +++ b/src/Cohesity.Powershell/Scripts/Restore/Restore-CohesityRemoteMSSQLObject.ps1 @@ -16,6 +16,9 @@ function Restore-CohesityRemoteMSSQLObject { Get the source instance id, $mssqlObjects[0].SnapshottedSource.SqlProtectionSource.OwnerId Use the DbRestoreOverwritePolicy:$true for overriding the existing database .EXAMPLE + 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 + .EXAMPLE Restore-CohesityRemoteMSSQLObject -SourceId 3101 -HostSourceId 3099 -JobId 51275 -TargetHostId 3098 -CaptureTailLogs:$false -NewDatabaseName ReportServer_r26 -NewInstanceName MSSQLSERVER -TargetDataFilesDirectory "C:\temp" -TargetLogFilesDirectory "C:\temp" -StartTime 1616956306627994 -JobRunId 60832 -RestoreTimeSecs 1616958037 Request for restore MSSQL object with RestoreTimeSecs (point in time) parameter, StartTime and JobRunId. .EXAMPLE @@ -33,11 +36,11 @@ function Restore-CohesityRemoteMSSQLObject { [Parameter(Mandatory = $false)] # Specifies the name of the restore task. [string]$TaskName = "Restore-MSSQL-Object-" + (Get-Date -Format "dddd-MM-dd-yyyy-HH-mm-ss").ToString(), - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [ValidateRange(1, [long]::MaxValue)] # Specifies the source id of the MS SQL database to restore. This can be obtained using Find-CohesityObjectsForRestore -Environments KSQL. [long]$SourceId, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [ValidateRange(1, [long]::MaxValue)] # Specifies the id of MSSQL database instance. [long]$HostSourceId, @@ -99,7 +102,16 @@ function Restore-CohesityRemoteMSSQLObject { [ValidateRange(1, [long]::MaxValue)] # Specifies the target host if the application is to be restored to a different host. # If not specified, then the application is restored to the original host (physical or virtual) that hosted this application. - [long]$TargetHostId + [long]$TargetHostId, + [Parameter(Mandatory = $false)] + # Specifies the SQL Host information + [string]$SqlHost, + [Parameter(Mandatory = $false)] + # Specifies the SQL Object Name + [string]$SqlObjectName, + [Parameter(Mandatory = $false)] + # Specifies the target host to restore + [string]$TargetHost ) Begin { } @@ -113,11 +125,26 @@ function Restore-CohesityRemoteMSSQLObject { } if ($job.IsActive -eq $false) { + if ($TargetHost) { + # Find the Id of specified target host + $protectionSources = Get-CohesityProtectionSource -Environments KSQL + foreach ($record in $protectionSources) { + if ($record.protectionSource.Name -eq $TargetHost) { + $TargetHostId = $record.protectionSource.id + break; + } + } - $protectionSourceObject = Get-CohesityProtectionSource -Id $TargetHostId - if ($protectionSourceObject.id -ne $TargetHostId) { - Write-Output "Cannot proceed, the target host id '$TargetHostId' is invalid" - return + if (!$TargetHostId){ + Write-Output "Unable to find the id of target host '$TargetHost'." + return + } + } elseif ($TargetHostId){ + $protectionSourceObject = Get-CohesityProtectionSource -Id $TargetHostId + if ($protectionSourceObject.id -ne $TargetHostId) { + Write-Output "Cannot proceed, the target host id '$TargetHostId' is invalid" + return + } } $searchedVMDetails = $null @@ -134,6 +161,29 @@ function Restore-CohesityRemoteMSSQLObject { return } + if ($SqlHost) { + # 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 } + + $vmList = $searchVMResult.vms + foreach ($vm in $vmList) { + if ($vm.vmDocument.objectAliases[0] -eq $SqlHost) { + foreach ($record in $sqlRecords) { + if ($vm.vmDocument.objectId.entity.sqlEntity.ownerId -eq $record.SnapshottedSource.ParentId) { + $SourceId = $record.SnapshottedSource.Id + $HostSourceId = $record.SnapshottedSource.ParentId + break + } + } + } + } + } + + if (!$SourceId) { + Write-Output "Please provide source information." + return + } + $searchedVMDetails = $searchResult.vms | Where-Object { ($_.vmDocument.objectId.jobId -eq $JobId) -and ($_.vmDocument.objectId.entity.id -eq $SourceId) } if ($searchTotalCount -eq 0) { @@ -142,8 +192,8 @@ function Restore-CohesityRemoteMSSQLObject { } if ($searchedVMDetails) { - $errorMsg = "Found database with search index " + $searchIndex + ", and total item count " + $searchTotalCount - CSLog -Message $errorMsg + $infoMsg = "Found database with search index " + $searchIndex + ", and total item count " + $searchTotalCount + CSLog -Message $infoMsg $continuePagination = $false } @@ -164,11 +214,23 @@ function Restore-CohesityRemoteMSSQLObject { } if (-not $JobRunId) { + # 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 - $run = $runs[0] - $JobRunId = $run.backupRun.jobRunId - $StartTime = $run.backupRun.stats.startTimeUsecs + 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 + } + } } + if (-not $NewDatabaseName) { $NewDatabaseName = $searchedVMDetails.vmDocument.objectId.entity.sqlEntity.databaseName } @@ -226,7 +288,7 @@ function Restore-CohesityRemoteMSSQLObject { $MSSQL_OBJECT_RESTORE_TYPE = 3 $MSSQL_TARGET_PHYSICAL_ENTITY_HOST_TYPE = 1 $MSSQL_TARGET_PHYSICAL_ENTITY_TYPE = 1 - $targetHost = [PSCustomObject]@{ + $targetHostObject = [PSCustomObject]@{ id = $TargetHostId } $targetHostParentSource = $null @@ -236,8 +298,8 @@ function Restore-CohesityRemoteMSSQLObject { type = $MSSQL_TARGET_VMWARE_ENTITY_TYPE name = $protectionSourceObject.vmWareProtectionSource.name } - $targetHost | Add-Member -NotePropertyName parentId -NotePropertyValue $protectionSourceObject.parentId - $targetHost | Add-Member -NotePropertyName vmwareEntity -NotePropertyValue $vmwareEntity + $targetHostObject | Add-Member -NotePropertyName parentId -NotePropertyValue $protectionSourceObject.parentId + $targetHostObject | Add-Member -NotePropertyName vmwareEntity -NotePropertyValue $vmwareEntity $targetHostParentSource = @{ id = $protectionSourceObject.parentId } @@ -252,9 +314,9 @@ function Restore-CohesityRemoteMSSQLObject { hostType = $MSSQL_TARGET_PHYSICAL_ENTITY_HOST_TYPE osName = $protectionSourceObject.physicalProtectionSource.osName } - $targetHost | Add-Member -NotePropertyName physicalEntity -NotePropertyValue $physicalEntity + $targetHostObject | Add-Member -NotePropertyName physicalEntity -NotePropertyValue $physicalEntity } - $targetHost | Add-Member -NotePropertyName type -NotePropertyValue $MSSQL_TARGET_HOST_TYPE + $targetHostObject | Add-Member -NotePropertyName type -NotePropertyValue $MSSQL_TARGET_HOST_TYPE $sqlRestoreParams = [PSCustomObject]@{ captureTailLogs = $CaptureTailLogs.IsPresent @@ -268,7 +330,7 @@ function Restore-CohesityRemoteMSSQLObject { alternateLocationParams = @{} } - if ($DbRestoreOverwritePolicy -eq $true) { + if ($DbRestoreOverwritePolicy -eq $true) { $sqlRestoreParams | Add-Member -NotePropertyName dbRestoreOverwritePolicy -NotePropertyValue "kOverwrite" } @@ -281,7 +343,7 @@ function Restore-CohesityRemoteMSSQLObject { appEntity = $searchedVMDetails.vmDocument.objectId.entity restoreParams = @{ sqlRestoreParams = $sqlRestoreParams - targetHost = $targetHost + targetHost = $targetHostObject targetHostParentSource = $targetHostParentSource } }