Tidy up and new file to create SA creds
This commit is contained in:
@@ -6,13 +6,13 @@
|
||||
$sqlInstance = "sqlfcsql\TESTINST"
|
||||
#$directory = "H:\Backup"
|
||||
$directory = "C:\Rubrik\mount"
|
||||
$fullBackupDay = 'Tuesday'
|
||||
$fullBackupDay = 'Thursday'
|
||||
$checkCluster = $false
|
||||
$logFile = "C:\Rubrik\backup.log"
|
||||
|
||||
$fullFlag = $directory + "\last_full.flag"
|
||||
$diffFlag = $directory + "\last_diff.flag"
|
||||
$today = (Get-Date).Date
|
||||
$logFile = "C:\Rubrik\backup.log"
|
||||
|
||||
function FlagTakenToday($flagPath) {
|
||||
if (Test-Path $flagPath) {
|
||||
@@ -58,6 +58,7 @@ if ((Get-Date).DayOfWeek -eq $fullBackupDay) {
|
||||
Write-Log "Selected FULL backup. Flag updated."
|
||||
} else {
|
||||
$backupType = "LOG"
|
||||
$cleanupTime = 24
|
||||
Write-Log "FULL backup already taken today. Selected LOG backup."
|
||||
}
|
||||
} else {
|
||||
|
||||
274
createSAcreds.ps1
Normal file
274
createSAcreds.ps1
Normal file
@@ -0,0 +1,274 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create a one-shot scheduled task that runs as a gMSA or service account to create a Rubrik service-account file.
|
||||
|
||||
.DESCRIPTION
|
||||
- Creates a temporary PowerShell script that calls Set-RscServiceAccountFile with given parameters.
|
||||
- Registers a scheduled task whose principal is either a gMSA or regular service account.
|
||||
- Starts the task, waits for completion, checks LastTaskResult, then optionally cleans up.
|
||||
|
||||
.PARAMETER Domain
|
||||
The AD domain (e.g. AD). If already providing fully-qualified account, set to empty string.
|
||||
|
||||
.PARAMETER AccountName
|
||||
The name of the service account. For gMSA, do not include trailing $. For regular accounts, use the username.
|
||||
|
||||
.PARAMETER AccountType
|
||||
Type of account: 'gMSA' or 'ServiceAccount'. Default: 'gMSA'
|
||||
|
||||
.PARAMETER Password
|
||||
Password for regular service accounts. Not used for gMSA accounts. Can be SecureString or plain text.
|
||||
|
||||
.PARAMETER SaJsonPath
|
||||
Full local path to the sa.json file that RubrikSecurityCloud module will use.
|
||||
|
||||
.PARAMETER OutputXmlPath
|
||||
Full local path to the output xml service account file (sa-rbksql.xml).
|
||||
|
||||
.PARAMETER TaskName
|
||||
(Optional) Scheduled task name. Default: CreateRubrikSAFile-<timestamp>
|
||||
|
||||
.PARAMETER KeepArtifacts
|
||||
If $true, keep the temporary script and task after completion. Default $false = cleanup.
|
||||
|
||||
.EXAMPLE
|
||||
# Using gMSA
|
||||
.\createSAcreds.ps1 -Domain AD -AccountName rubrikgmsa -AccountType gMSA -SaJsonPath C:\temp\sa.json -OutputXmlPath C:\temp\sa-rbksql.xml
|
||||
|
||||
.EXAMPLE
|
||||
# Using regular service account with password prompt
|
||||
.\createSAcreds.ps1 -Domain AD -AccountName rbksql -AccountType ServiceAccount -Password (Read-Host -AsSecureString -Prompt "Enter SA password") -SaJsonPath C:\Rubrik\scripts\sa.json -OutputXmlPath C:\Rubrik\scripts\sa-real.xml
|
||||
|
||||
.EXAMPLE
|
||||
# Using regular service account with plain text password
|
||||
.\createSAcreds.ps1 -Domain AD -AccountName rbksql -AccountType ServiceAccount -Password "MyPassword123" -SaJsonPath C:\Rubrik\scripts\sa.json -OutputXmlPath C:\Rubrik\scripts\sa-real.xml
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$Domain,
|
||||
[Parameter(Mandatory=$true)][string]$AccountName,
|
||||
[ValidateSet('gMSA', 'ServiceAccount')][string]$AccountType = 'gMSA',
|
||||
[object]$Password,
|
||||
[Parameter(Mandatory=$true)][string]$SaJsonPath,
|
||||
[Parameter(Mandatory=$true)][string]$OutputXmlPath,
|
||||
[string]$TaskName = "CreateRubrikSAFile-$((Get-Date).ToString('yyyyMMdd-HHmmss'))",
|
||||
[switch]$KeepArtifacts
|
||||
)
|
||||
|
||||
try {
|
||||
# ---- Parameter validation ----
|
||||
if ($AccountType -eq 'ServiceAccount' -and -not $Password) {
|
||||
# Prompt for password if not provided for service accounts
|
||||
Write-Host "Password required for service account '$AccountName'"
|
||||
$Password = Read-Host -AsSecureString -Prompt "Enter password for $AccountName"
|
||||
}
|
||||
|
||||
if ($AccountType -eq 'gMSA' -and $Password) {
|
||||
Write-Warning "Password parameter ignored for gMSA accounts"
|
||||
}
|
||||
|
||||
# ---- Basic validation ----
|
||||
if (-not (Test-Path -Path $SaJsonPath)) { throw "SA JSON not found at: $SaJsonPath" }
|
||||
$tempDir = Join-Path -Path $env:TEMP -ChildPath "CreateRubrikSAFile_$([guid]::NewGuid().ToString().Substring(0,8))"
|
||||
New-Item -Path $tempDir -ItemType Directory -Force | Out-Null
|
||||
|
||||
$oneShotScript = Join-Path $tempDir "Create-SA-File.ps1"
|
||||
$logFile = Join-Path $tempDir "Create-SA-File.log"
|
||||
|
||||
# ---- Create the one-shot script that will run under the service account ----
|
||||
$oneShotContent = @"
|
||||
# One-shot script created by create-and-run-one-shot-via-gMSA.ps1
|
||||
# Runs RubrikSecurityCloud command to create service-account file
|
||||
|
||||
# Start transcript for detailed logging
|
||||
Start-Transcript -Path `"$logFile`" -Append
|
||||
|
||||
Write-Output "Script started at: `$(Get-Date)"
|
||||
Write-Output "Running as user: `$([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"
|
||||
Write-Output "PowerShell version: `$(`$PSVersionTable.PSVersion)"
|
||||
|
||||
Try {
|
||||
Write-Output "Attempting to import RubrikSecurityCloud module..."
|
||||
Import-Module RubrikSecurityCloud -ErrorAction Stop
|
||||
Write-Output "Successfully imported RubrikSecurityCloud module"
|
||||
} Catch {
|
||||
Write-Error "Failed to import RubrikSecurityCloud module: `$(`$_.Exception.Message)"
|
||||
Write-Error "Full exception: `$(`$_.Exception | Format-List * | Out-String)"
|
||||
Stop-Transcript
|
||||
Exit 2
|
||||
}
|
||||
|
||||
Try {
|
||||
Write-Output "Checking input file: $SaJsonPath"
|
||||
# Ensure the input file exists
|
||||
if (-not (Test-Path -Path `"$SaJsonPath`")) {
|
||||
Write-Error "Input SA JSON not found: $SaJsonPath"
|
||||
Stop-Transcript
|
||||
Exit 3
|
||||
}
|
||||
Write-Output "Input file found, size: `$((Get-Item `"$SaJsonPath`").Length) bytes"
|
||||
|
||||
Write-Output "Calling Set-RscServiceAccountFile..."
|
||||
Write-Output " Input: $SaJsonPath"
|
||||
Write-Output " Output: $OutputXmlPath"
|
||||
|
||||
Set-RscServiceAccountFile `"$SaJsonPath`" -OutputFilePath `"$OutputXmlPath`" -Verbose
|
||||
|
||||
Write-Output "Set-RscServiceAccountFile completed"
|
||||
|
||||
if (Test-Path -Path `"$OutputXmlPath`") {
|
||||
Write-Output "Service account XML created successfully: $OutputXmlPath"
|
||||
Write-Output "Output file size: `$((Get-Item `"$OutputXmlPath`").Length) bytes"
|
||||
Stop-Transcript
|
||||
Exit 0
|
||||
} else {
|
||||
Write-Error "Set-RscServiceAccountFile completed but output file not found: $OutputXmlPath"
|
||||
Write-Error "Checking parent directory: `$(Split-Path `"$OutputXmlPath`")"
|
||||
if (Test-Path (Split-Path `"$OutputXmlPath`")) {
|
||||
Write-Output "Parent directory exists, listing contents:"
|
||||
Get-ChildItem (Split-Path `"$OutputXmlPath`") | ForEach-Object { Write-Output " `$(`$_.Name)" }
|
||||
} else {
|
||||
Write-Error "Parent directory does not exist: `$(Split-Path `"$OutputXmlPath`")"
|
||||
}
|
||||
Stop-Transcript
|
||||
Exit 4
|
||||
}
|
||||
} Catch {
|
||||
Write-Error "Error creating RBK service-account file: `$(`$_.Exception.Message)"
|
||||
Write-Error "Full exception: `$(`$_.Exception | Format-List * | Out-String)"
|
||||
Write-Error "Stack trace: `$(`$_.ScriptStackTrace)"
|
||||
Stop-Transcript
|
||||
Exit 5
|
||||
}
|
||||
"@
|
||||
|
||||
# Replace placeholders (so we don't have to escape too much)
|
||||
$oneShotContent = $oneShotContent -replace '\$SaJsonPath', [Regex]::Escape($SaJsonPath)
|
||||
$oneShotContent = $oneShotContent -replace '\$OutputXmlPath', [Regex]::Escape($OutputXmlPath)
|
||||
$oneShotContent = $oneShotContent -replace '\$logFile', [Regex]::Escape($logFile)
|
||||
|
||||
Set-Content -Path $oneShotScript -Value $oneShotContent -Encoding UTF8
|
||||
|
||||
# Make sure executable by scheduled task
|
||||
icacls $oneShotScript /grant "BUILTIN\Administrators:(R,W)" | Out-Null
|
||||
|
||||
# ---- Build Scheduled Task objects ----
|
||||
# Construct the UserId based on account type
|
||||
if ($AccountType -eq 'gMSA') {
|
||||
$userId = if ([string]::IsNullOrWhiteSpace($Domain)) { "$AccountName`$" } else { "$Domain\$AccountName`$" }
|
||||
$logonType = 'Password' # For gMSA, use Password logon type
|
||||
} else {
|
||||
$userId = if ([string]::IsNullOrWhiteSpace($Domain)) { $AccountName } else { "$Domain\$AccountName" }
|
||||
$logonType = 'Password' # For regular service accounts, use Password logon type
|
||||
}
|
||||
|
||||
# Action: run PowerShell to execute the one-shot script with output redirection
|
||||
$psArgs = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$oneShotScript`" *>&1 | Tee-Object -FilePath `"$logFile`" -Append"
|
||||
$action = New-ScheduledTaskAction -Execute (Join-Path $env:WINDIR 'System32\WindowsPowerShell\v1.0\powershell.exe') -Argument $psArgs
|
||||
|
||||
# Trigger: once, a short time in the future (1 minute from now)
|
||||
$startTime = (Get-Date).AddMinutes(1)
|
||||
$trigger = New-ScheduledTaskTrigger -Once -At $startTime
|
||||
|
||||
# Principal: service account or gMSA
|
||||
$principal = New-ScheduledTaskPrincipal -UserId $userId -LogonType $logonType -RunLevel Highest
|
||||
|
||||
# Settings: one-shot, don't persist run as logged on user UI
|
||||
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 1)
|
||||
|
||||
$task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger -Settings $settings
|
||||
|
||||
# ---- Register the scheduled task ----
|
||||
if ($AccountType -eq 'gMSA') {
|
||||
# For gMSA, register without password (AD will handle authentication)
|
||||
Register-ScheduledTask -TaskName $TaskName -InputObject $task -Force
|
||||
Write-Host "Registered scheduled task '$TaskName' to run as gMSA $userId at $startTime."
|
||||
} else {
|
||||
# For regular service accounts, register with password
|
||||
$securePassword = if ($Password -is [SecureString]) { $Password } else { ConvertTo-SecureString $Password -AsPlainText -Force }
|
||||
Register-ScheduledTask -TaskName $TaskName -InputObject $task -User $userId -Password ([Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword))) -Force
|
||||
Write-Host "Registered scheduled task '$TaskName' to run as service account $userId at $startTime."
|
||||
}
|
||||
|
||||
# Optionally start immediately (Start-ScheduledTask will ignore trigger time and try to run it)
|
||||
Start-ScheduledTask -TaskName $TaskName
|
||||
Write-Host "Started task. Waiting for completion..."
|
||||
|
||||
# ---- Wait for completion and inspect result ----
|
||||
$maxWaitSeconds = 600
|
||||
$pollInterval = 3
|
||||
$elapsed = 0
|
||||
$lastResult = $null
|
||||
$taskCompleted = $false
|
||||
|
||||
while ($true) {
|
||||
Start-Sleep -Seconds $pollInterval
|
||||
$elapsed += $pollInterval
|
||||
|
||||
$info = Get-ScheduledTaskInfo -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
if ($null -eq $info) {
|
||||
Write-Warning "Could not query task info yet."
|
||||
} else {
|
||||
# LastTaskResult returns Win32 error code; 0 = success
|
||||
$lastResult = $info.LastTaskResult
|
||||
$state = $info.State
|
||||
Write-Host "Task state: '$state'; LastResult: $lastResult"
|
||||
|
||||
# Task is complete if:
|
||||
# 1. State is Ready/Disabled/Unknown AND we have a valid LastResult
|
||||
# 2. OR if LastResult changed from 267009 (SCHED_S_TASK_RUNNING) to something else
|
||||
if (($state -eq 'Ready' -or $state -eq 'Disabled' -or $state -eq 'Unknown' -or [string]::IsNullOrEmpty($state)) -and
|
||||
($lastResult -ne $null -and $lastResult -ne 267009)) {
|
||||
$taskCompleted = $true
|
||||
break
|
||||
}
|
||||
|
||||
if ($state -eq 'Running') {
|
||||
Write-Host "Task still running..."
|
||||
}
|
||||
}
|
||||
|
||||
if ($elapsed -ge $maxWaitSeconds) {
|
||||
throw "Timed out waiting for scheduled task to finish (waited $maxWaitSeconds seconds)."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Task completed after $elapsed seconds."
|
||||
|
||||
# ---- Check exit status and output ----
|
||||
if ($lastResult -eq 0) {
|
||||
Write-Host "Task finished successfully (LastTaskResult=0)."
|
||||
if (Test-Path -Path $OutputXmlPath) {
|
||||
Write-Host "Found output XML: $OutputXmlPath"
|
||||
} else {
|
||||
Write-Warning "Task indicated success but output file not found at $OutputXmlPath"
|
||||
}
|
||||
} else {
|
||||
Write-Host "Scheduled task finished with non-zero LastTaskResult: $lastResult"
|
||||
|
||||
# Display log file contents for troubleshooting
|
||||
if (Test-Path -Path $logFile) {
|
||||
Write-Host "`n--- Log file contents ($logFile) ---"
|
||||
Get-Content -Path $logFile | ForEach-Object { Write-Host $_ }
|
||||
Write-Host "--- End of log file ---`n"
|
||||
} else {
|
||||
Write-Warning "Log file not found at: $logFile"
|
||||
}
|
||||
|
||||
throw "Scheduled task finished with non-zero LastTaskResult: $lastResult. Check Event Viewer > Applications and Services Logs > Microsoft > Windows > TaskScheduler for details, or review the log output above."
|
||||
}
|
||||
|
||||
# ---- Cleanup ----
|
||||
if (-not $KeepArtifacts) {
|
||||
Write-Host "Cleaning up task and temporary files..."
|
||||
try { Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue } catch {}
|
||||
try { Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue } catch {}
|
||||
Write-Host "Cleanup complete."
|
||||
} else {
|
||||
Write-Host "Kept task '$TaskName' and temporary script at: $oneShotScript"
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Error "ERROR: $($_.Exception.Message)"
|
||||
throw
|
||||
}
|
||||
Reference in New Issue
Block a user