Last active
July 18, 2019 11:35
-
-
Save Brad-Christie/8093b1e262f9dca62f9614e6fbfad8bd to your computer and use it in GitHub Desktop.
Backup Sitecore Instance (Single Developer Only)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Function GetDatabases { | |
[CmdletBinding()] | |
Param( | |
[Parameter(Position = 0, Mandatory, ValueFromPipeline)] | |
[ValidateScript({ Test-Path $_ -PathType "Container" })] | |
[string]$WebRoot | |
) | |
Process { | |
$Databases = @() | |
Function TestIsSqlConnectionString([string]$ConnectionString) { | |
Try { | |
[void]([System.Data.SqlClient.SqlConnectionStringBuilder]::new($ConnectionString)) | |
$true | |
} Catch { | |
$false | |
} | |
} | |
$connectionStringsPath = Join-Path $WebRoot -ChildPath "App_Config\ConnectionStrings.config" | |
If (!(Test-Path $connectionStringsPath)) { | |
Write-Warning "GetDatabases: ConnectionStrings.config '${connectionStringsPath}' does not exist." | |
Return $Databases | |
} | |
$connectionStringsXml = [xml](Get-Content $connectionStringsPath) | |
$connectionStrings = [System.Xml.XmlElement]$connectionStringsXml.SelectSingleNode("//connectionStrings") | |
If ($null -ne $connectionStrings) { | |
$connectionStrings.SelectNodes("add") | ForEach-Object { | |
$add = [System.Xml.XmlElement]$_ | |
$connectionString = $add.GetAttribute("connectionString") | |
If (!(TestIsSqlConnectionString $connectionString)) { | |
Return # aka "Continue" in ForEach-Object | |
} | |
If (!([string]::IsNullOrWhiteSpace($connectionString))) { | |
$name = $add.GetAttribute("name") | |
If (!([string]::IsNullOrEmpty($name))) { | |
$sqlConnectionString = [System.Data.SqlClient.SqlConnectionStringBuilder]::new($connectionString) | |
$databaseName = $sqlConnectionString.InitialCatalog | |
$dataSource = $sqlConnectionString.DataSource | |
If (!([string]::IsNullOrWhiteSpace($databaseName))) { | |
$exist = $null -ne ($Databases | Where-Object { $_.DatabaseName -eq $databaseName -and $_.DataSource -eq $dataSource }) | |
If (!$exist) { | |
Write-Host "AddDatabases: Adding ${databaseName}" | |
$Databases += @{ | |
Name = $name | |
DatabaseName = $databaseName | |
DataSource = $dataSource | |
ConnectionString = $connectionString | |
} | |
} Else { | |
Write-Host "AddDatabases: Skipped ${databaseName} (${connectionString}) [Exists]" | |
} | |
} | |
} | |
} | |
} | |
$configSource = $connectionStrings.GetAttribute("ConfigSource") | |
If (!([string]::IsNullOrWhiteSpace($configSource))) { | |
$configSourcePath = Join-Path $WebRoot -ChildPath $configSource | |
If (!(Test-Path $configSourcePath)) { | |
Write-Warning "GetDatabases: ConfigSource '${configSourcePath}' does not exist." | |
Return $Databases | |
} | |
} | |
} Else { | |
Write-Warning "GetDatabases: connectionStrings not found." | |
} | |
Return $Databases | |
} | |
} | |
Function BackupDatabase { | |
[CmdletBinding()] | |
Param( | |
[Parameter(Mandatory, ValueFromPipeline)] | |
[ValidateNotNullOrEmpty()] | |
[psobject[]]$Database | |
, | |
[Parameter(Position = 0, Mandatory)] | |
[ValidateScript({ Test-Path $_ -IsValid })] | |
[string]$Destination | |
, | |
[Parameter()] | |
[Alias("Username", "SAUsername")] | |
[string]$DatabaseAdminUsername = "sa" | |
, | |
[Parameter()] | |
[Alias("Password", "SAPassword")] | |
[string]$DatabaseAdminPassword | |
) | |
Process { | |
If (!(Test-Path $Destination)) { | |
New-Item $Destination -ItemType "Directory" | Out-Null | |
} | |
$databaseName = $Database.DatabaseName | |
$connectionString = $Database.ConnectionString | |
$backupFilePath = Join-Path $Destination -ChildPath ("${databaseName}_{0}.bak" -f (Get-Date -UFormat "%Y%m%d")) | |
$backupName = "{0} backup {1}" -f $databaseName, (Get-Date -UFormat "%Y%m%d") | |
$query = "BACKUP DATABASE [${databaseName}] TO " + | |
"DISK = N'${backupFilePath}' WITH NOFORMAT, NOINIT, " + | |
"NAME = N'${backupName}', SKIP, NOREWIND, NOUNLOAD, STATS = 10" | |
If (!([string]::IsNullOrWhiteSpace($DatabaseAdminPassword))) { | |
$connectionStringBuilder = [System.Data.SqlClient.SqlConnectionStringBuilder]::new($connectionString) | |
$connectionStringBuilder["User ID"] = $DatabaseAdminUsername | |
$connectionStringBuilder.Password = $DatabaseAdminPassword | |
$connectionString = $connectionStringBuilder.ToString() | |
} | |
Write-Host "Backing up ${DatabaseName} to ${backupFilePath}..." | |
Try { | |
Invoke-Sqlcmd -Query $query -ConnectionString $connectionString | |
} Catch { | |
Write-Warning "Unable to backup ${databaseName}: $($_.Exception.Message)" | |
} | |
} | |
} | |
Function BackupWebsite { | |
[CmdletBinding()] | |
Param( | |
[Parameter(Position = 0, Mandatory, ValueFromPipeline)] | |
[ValidateScript({ Test-Path $_ -PathType "Container" })] | |
[string]$WebRoot | |
, | |
[Parameter(Position = 1, Mandatory)] | |
[ValidateScript({ Test-Path $_ -PathType "Container" })] | |
[string]$DestinationPath | |
) | |
Process { | |
$backupFilePath = Join-Path $DestinationPath -ChildPath (Get-Date -UFormat "Website_%Y%m%d.zip") | |
Get-ChildItem $WebRoot -Recurse | Compress-Archive -DestinationPath $backupFilePath -CompressionLevel "Optimal" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
. "${PSScriptRoot}\Backup-Sitecore.ps1" | |
$WebRoot = "C:\inetpub\wwwroot\habitathome.dev.local" | |
$BackupPath = Join-Path $env:TEMP -ChildPath (New-Guid).ToString("d") | |
$SAUsername = "SA" | |
$SAPassword = "Str0NgPA33w0rd!!" | |
Try { | |
New-Item $BackupPath -ItemType Directory | Out-Null | |
# Give SQL permissions to the directory otherwise you get access is denied | |
$acl = Get-Acl $BackupPath | |
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("NT SERVICE\MSSQLSERVER","FullControl","Allow") | |
$acl.SetAccessRule($accessRule) | |
$acl | Set-Acl $BackupPath | |
# Appears SC's WDP (when creating SQL accounts) doesn't add DB_BACKUPOPERATOR role | |
# so we need to leverage SA account when performing backups | |
# Backs up DBs to DBNAME_YYMMDD.bak | |
GetDatabases $WebRoot | BackupDatabase -Destination $BackupPath -DatabaseAdminUsername $SAUsername -DatabaseAdminPassword $SAPassword | |
# Backs up website directory to Website_YYMMDD.zip | |
BackupWebsite $WebRoot -DestinationPath $BackupPath | |
} Finally { | |
Get-ChildItem "${BackupPath}\*" -Recurse | Write-Output | |
# Cleanup while developing...(using $env:TEMP) | |
#Remove-item $BackupPath -Recurse | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Future Enhancements: