Comprehensive data protection for all workloads
Post Reply
ryan1cf
Service Provider
Posts: 26
Liked: 3 times
Joined: Apr 19, 2017 3:47 pm
Full Name: Ryan Faulkner
Contact:

SureBackup and a Powershell script

Post by ryan1cf »

Hello all,

I'm trying to setup a SureBackup job, with a backup protected Windows VM, where a script is added to the SureBackup job that will run chkdsk on the booted up SureBackup VM.
I'm confused about how I need to use the Arguments field within the Test Scripts window along with the selected ps1 script. Do I have to make the powershell script itself connect to the Veeam Lab VM itself? I assume the ps1 script will have to have lines for connecting to a remote Server using %vm_ip% or $server = "%vm_ip% this is the part I'm confused about, how do I get the script in the job and the ps1 script connecting to the powered up SureBackup VM?

I've been looking in https://github.com/VeeamHub/powershell/tree/master and reading this script https://github.com/VeeamHub/powershell/ ... etcred.ps1 where it appears where $server = "localhost" is used and within the SureBackup job arguments I think -server %vm_ip% is connected back to that localhost in the script?

Any help at all is appreciated, thanks!
Ryan
HannesK
Product Manager
Posts: 15146
Liked: 3242 times
Joined: Sep 01, 2014 11:46 am
Full Name: Hannes Kasparick
Location: Austria
Contact:

Re: SureBackup and a Powershell script

Post by HannesK »

Hello,
yes, the script needs to connect to the VM. This thread has some examples for PowerShell

As far as I see, the example script from Github needs to be adjusted. The $server variable is set static and needs to be replaced by the server name / IP. I don't see any external parameter input in that script.

Best regards,
Hannes
ryan1cf
Service Provider
Posts: 26
Liked: 3 times
Joined: Apr 19, 2017 3:47 pm
Full Name: Ryan Faulkner
Contact:

Re: SureBackup and a Powershell script

Post by ryan1cf »

Hi Hannes,

Thank you for the reply. Can I tell the powershell script to use either the %vm_fqdn% or %vm_fqdn% or do I have to statically program in the ps script the IP address of the masquerade IP? Do you know of any example powershell scripts and SureBackup job settings that run powershell scripts on remote Servers?

Thanks,
Ryan
ryan1cf
Service Provider
Posts: 26
Liked: 3 times
Joined: Apr 19, 2017 3:47 pm
Full Name: Ryan Faulkner
Contact:

Re: SureBackup and a Powershell script

Post by ryan1cf »

Hit a snag. Got a script working manually, but Veeam apparently can't connect to the CredentialManager without creds, defeats the purpose of not storing creds within my script.

snippet of task.application_group.log
[13.09.2023 11:50:28.686] <73> Info [SureBackup] [X] [ScriptTests] [Console] Get-StoredCredential : CredRead failed with the error code 1312.
[13.09.2023 11:50:28.687] <73> Info [SureBackup] [X] [ScriptTests] [Console] At C:\VeeamScript\VeeamScript1.ps1:10 char:12
[13.09.2023 11:50:28.687] <73> Info [SureBackup] [X] [ScriptTests] [Console] + $MyCreds = Get-StoredCredential -Target 'domainadmin'
[13.09.2023 11:50:28.687] <73> Info [SureBackup] [X] [ScriptTests] [Console] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[13.09.2023 11:50:28.687] <73> Info [SureBackup] [X] [ScriptTests] [Console] + CategoryInfo : InvalidOperation: (domainadmin:String) [Get-Stor
[13.09.2023 11:50:28.687] <73> Info [SureBackup] [X] [ScriptTests] [Console] edCredential], Exception
[13.09.2023 11:50:28.687] <73> Info [SureBackup] [X] [ScriptTests] [Console] + FullyQualifiedErrorId : 1,PSCredentialManager.Cmdlet.GetStoredCredential
[13.09.2023 11:50:28.687] <73> Info [SureBackup] [x] [ScriptTests] [Console]
[13.09.2023 11:50:28.690] <73> Info [SureBackup] [X] [ScriptTests] [Console] WARNING: Unable to convert Credential object without username or password to
[13.09.2023 11:50:28.690] <73> Info [SureBackup] [X] [ScriptTests] [Console] PSCredential object

Here is my actual ps script that's setup in the application group:

#input the target IP of the remote machine
$target = "192.168.255.203"

#get creds from CredentialManager
$MyCreds = Get-StoredCredential -Target 'domainadmin'

#run the script on the remote machine
Invoke-Command -ComputerName $target -FilePath c:\VeeamScript\chkdsk_test_editing-final.ps1 -credential $MyCreds



__________________
I had tried using a stored credential text file but Veeam/SureBackup couldn't read or find the file...

Not sure where to go from here.
tdewin
Veeam Software
Posts: 1838
Liked: 661 times
Joined: Mar 02, 2012 1:40 pm
Full Name: Timothy Dewin
Contact:

Re: SureBackup and a Powershell script

Post by tdewin »

It's a 6 year old script but param allows you to pass -server option. That is the idea. Also this uses netcred, eg basically it uses the credentials that you can set on the surebackup script configuration post433126.html

You don't need to extract the credentials yourself, it uses the netcreds by using this connection statement "Integrated Security=True;". Basically, surebackup starts up the script with the supplied credentials (set netcreds), and the script connects with the supplied credentials.
ryan1cf
Service Provider
Posts: 26
Liked: 3 times
Joined: Apr 19, 2017 3:47 pm
Full Name: Ryan Faulkner
Contact:

Re: SureBackup and a Powershell script

Post by ryan1cf »

The fine folks at Veeam support pointed me in the right direction, to this article: https://vnote42.net/2022/05/23/using-cu ... ment-17780

Couple of things to note:
#1 - under the 4. Write start script, the script must start with Param as shown, nothing can be in front or above it, otherwise Param won't be recognized
#2 - also under the 4. Write start script, the -ScriptBlock must be immediately followed by the { character, so not as they show where it's in a line below and has spaces in front.

I want to share this with everyone as it became useful to us, but here is the final chkdsk script and leading start, the chkdsk script checks all volumes on the booted up SureBackup Veeam Lab isolated Windows machine for ntfs integrity errors and if any are found a file is created and then the script exits 1 if that file is found, which is the error code that SureBackup will detect and use as indication of a failure so the job will show failed.

This gets added to the application group test scripts, using as the article above shows and adding the %vm_ip% to the Arguments. I also tested with a domain admin account and that failed as the VM doesn't have access to the domain and it doesn't appear to accept cached creds on the VM, so I used a local admin account on the VM.

I did not create the script after PHASE 1, other than adding in the changes I needed so it would exit and create a file if an error was found during chkdsk. I further plan to re-adapt this using Repair-Volume rather than chkdsk.

Create any name ps1 script with the data immediately below:
Param($TestVmIP)
$ReturnCode = 1
$CredObject = Import-Clixml -Path C:\VeeamScript\CredObject.xml
$ReturnCode = Invoke-Command -Credential $CredObject -Computername $TestVmIP -ErrorAction Stop -ScriptBlock{

### Start of script code

$ReturnFail = 1
$ReturnSuccess = 0

<#
PHASE 1: OPERATING SYSTEM INFO
#>

# Getting OS info and displaying it

Write-Output "Computer hostname is $env:computername"

$folderPath = "c:\temp"
if (!(Test-Path $folderPath -PathType Container)) {
New-Item -ItemType Directory -Force -Path $folderPath
}

New-Item en-CA.txt
New-Item en-US.txt
Add-Content en-US.txt ("8= Windows has scanned the file system and found no problems;No further action is required; 0 KB in bad sectors")
Add-Content en-US.txt ("7= Windows has checked the file system and found no problems; 0 KB in bad sectors")
Add-Content en-US.txt ("bad= bad sectors")
Add-Content en-CA.txt ("8= Windows has scanned the file system and found no problems;No further action is required; 0 KB in bad sectors")
Add-Content en-CA.txt ("7= Windows has checked the file system and found no problems; 0 KB in bad sectors")
Add-Content en-CA.txt ("bad= bad sectors")

$os_info = Get-WmiObject -Class Win32_OperatingSystem

Write-Output "Operating system is $($os_info.Caption), version $($os_info.Version)"

# Getting OS build number

$os_build = [int] $os_info.BuildNumber

<#
PHASE 2: SUPPORTED LANGUAGES
#>

<#
ISO Language Code Table: http://www.lingoes.net/en/translator/langcode.htm

Supported languages are defined by TXT files containing translations of the "OK messages" you can find looking at the chkdsk event log.
Lang file needs to have the following three lines and syntax:

8= Message1;Message2;Message3
7= Message4;Message5;Message6
bad= bad sectors

After the "8= " you just write the message you can find in the logs for Windows 8/10; after the "7= " it is the same, but for Windows 7; after the "bad= " you write how to say "bad sectors" in that language.
Since this script will be uploaded as a component in Datto RMM, it will search for the TXT files inside of the current folder, exluding the command.ps1 file, that is the script itself.
#>

# Getting supported languages from TXT file list

$supported_lang =

Get-ChildItem -Path .\ |

Where-Object {$_.Name -ne "command.ps1"} |

ForEach-Object {

Write-Output $_.Name.TrimEnd(".txt")

}

# Checking if installed language is supported

Write-Output "Installed language is $((Get-Culture).DisplayName)"

# If not supported

if ($supported_lang -notcontains $PSCulture) {

# Stopping the script

Write-Output "Installed language is not supported."

exit 1

}

# Getting the lang file content

$lang_file = Get-Content -Path .\$PSCulture.txt

# Defining how to say "bad sectors" in the installed language

$bad_sectors = $lang_file[2].TrimStart("bad= ")

# Defining OK messages based on OS build

# If OS is Windows 8 or greater

if ($os_build -ge 9200) {

$ok_messages = $lang_file[0].TrimStart("8= ").Split(";")

# Also defining /scan parameter for chkdsk command

$scan = "/scan"

# If OS is Windows 7

} elseif ($os_build -lt 9200 -and $os_build -ge 7600) {

$ok_messages = $lang_file[1].TrimStart("7= ").Split(";")

# If OS is not not supported

} else {

# Stopping the script

Write-Output "Installed operating system is not supported."

exit 1

}

<#
PHASE 3: VOLUMES
#>

# Getting volumes where drive type is fixed and capacity is at least 200 MB

Get-WmiObject -Class Win32_Volume |

Where-Object {$_.DriveType -eq 3} |

Where-Object {$_.Capacity -ge 200000000} |

# For each volume found

ForEach-Object {

# Writing a message before starting showing the volume name and label

Write-Output "=============================================

Running Check Disk on volume $($_.Name)
Label: $($_.Label)
"

# Getting volume ID (used to run chkdsk command)

$volume_id = $_.DeviceID.TrimEnd("\")

# Creating a short volume ID removing forbidden characters (used to name the log file)

$volume_short_id = $volume_id.TrimStart("\\?\Volume{").TrimEnd("}")

<#
PHASE 4: LOGS
#>

# Creating a variable containing the logs folder's complete path

$logs_folder = "C:\chkdsk_logs"

# Creating a variable containing the log file's complete path (used to save it)

$log_path = "$logs_folder\chkdsk_log_$volume_short_id.log"

# Creating the logs folder

New-Item -ItemType Directory -Path C:\ -Name chkdsk_logs -ErrorAction SilentlyContinue |

Out-Null

<#
PHASE 5: CHECK DISK
#>

# Running chkdsk and saving log file

chkdsk $scan $volume_id |

Out-File -FilePath $log_path

# Checking if some of the OK messages are not found in the log file

$ok_messages |

# For each of the messages

ForEach-Object {

# Getting the content of the log file only if it contains one of the messages

$log_content = Get-Content -Path $log_path

$log_ok =

$log_content |

Select-String -Pattern $_

# If the found content is empty

if ($log_ok -eq $null) {

# Showing the OK message that is missing

Write-Output "Ok message missing, creating file c:\temp\chkdsk_errors_found.txt"
Write-Warning "The following message was not found in the log:
$_"
New-Item c:\temp\chkdsk_errors_found.txt

# If the found content is NOT empty

} else {

# Showing the OK message that is found

Write-Output "Showing each OK message that was found..."
Write-Output "$_
"

}

}

<#
PHASE 6: BAD SECTORS
#>

<#
This phase will compare current bad sectors with the ones from the last chkdsk.
If something has changed it will give a warning.
#>

# Creating a BadSectorsMonitor key in registry

New-Item -ItemType Directory -Path HKLM:\SOFTWARE\ -Name BadSectorsMonitor -ErrorAction SilentlyContinue |

Out-Null

# Getting bad sectors from log file

$current_bad_sectors =

$log_content |

Select-String -Pattern $bad_sectors

# Creating a string value in registry containing current bad sectors

New-ItemProperty -Path HKLM:\SOFTWARE\BadSectorsMonitor -Name CurrentBadSectors_$volume_short_id -Value $current_bad_sectors -Force |

Out-Null

# Defining previous bad sectors name and value

$previous_value_name = "PreviousBadSectors_$volume_short_id"

$previous_bad_sectors = (Get-ItemProperty -Path HKLM:\SOFTWARE\BadSectorsMonitor -Name $previous_value_name -ErrorAction SilentlyContinue).$previous_value_name

# If there is no value for previous bad sectors

if ($previous_bad_sectors -eq $null) {

# Creating value for previous bad sectors

New-ItemProperty -Path HKLM:\SOFTWARE\BadSectorsMonitor -Name $previous_value_name -Value $current_bad_sectors -Force |

Out-Null

# If there is a value for previous bad sectors

} else {

# Comparing the PreviousBadSectors value and the CurrentBadSectors value

# If they are equal

if ($previous_bad_sectors -eq $current_bad_sectors) {

Write-Output "Bad sectors have not changed since last chkdsk."

# If they are not equal

} else {

Write-Warning "Bad sectors have changed since last chkdsk."
Write-Warning "Previous: $previous_bad_sectors."
Write-Warning "Current: $current_bad_sectors."

}

# Overwriting the previous value with the current value

Set-ItemProperty -Path HKLM:\SOFTWARE\BadSectorsMonitor -Name $previous_value_name -Value $current_bad_sectors -Force |

Out-Null

}

}

# Writing a message when completed

Write-Output "=============================================

chkdsk completed on all volumes! Logs can be found in $logs_folder."

#final exit step, if any volume had errors then line 202 creates a file that we can check for and exit 1 if found.
Write-Output "Checking for presense of chkdsk errors file..."
$FileName = "c:\temp\chkdsk_errors_found.txt"
if (Test-Path $FileName) {
Write-Output "File Exists"
Write-Output "Chkdsk errors file was found, this means chkdsk errors were found, read the logs, exiting script with exit 1"
$ReturnFail
}
else
{
Write-Output "No chkdsk errors file found so not chkdsk errors were found, exiting script with exit 0."
$ReturnSuccess
}
### End of script code

}
### end of initiator script

exit $ReturnCode
ryan1cf
Service Provider
Posts: 26
Liked: 3 times
Joined: Apr 19, 2017 3:47 pm
Full Name: Ryan Faulkner
Contact:

Re: SureBackup and a Powershell script

Post by ryan1cf »

My script above though working, isn't working properly with Veeam, no matter the exit code within the code script itself, the part that is run on the powered on SureBackup VM, the job always ends in code 0 as success, so that part still isn't working here. So I don't know if it's my syntax or Veeam itself yet, I'm leaning towards my syntax.
dharmandds
Service Provider
Posts: 2
Liked: never
Joined: Jul 10, 2019 2:44 pm
Full Name: Darrin Harman
Contact:

Re: SureBackup and a Powershell script

Post by dharmandds »

You aren't providing an exit code. You have your exit code inside the quotes for your write-host, so you're just telling PowerShell to write some text and it won't interpret it as the exit code.

In the lines where you have $ReturnFail and $ReturnSuccess, you need to call Exit. You might be able to do this
Exit $ReturnSuccess
or
Exit $ReturnFail
since you are setting those values earlier in the script. You could also just not worry about setting those values and just do
#Exit with Success
Exit 0

and
#Exit with fail
Exit 1
ryan1cf
Service Provider
Posts: 26
Liked: 3 times
Joined: Apr 19, 2017 3:47 pm
Full Name: Ryan Faulkner
Contact:

Re: SureBackup and a Powershell script

Post by ryan1cf »

Hey dharmandds,

I figured out the problem is that if my script exits with "exit 0" powershell is adding extra breaks. I have been able to get it to exit 1 without extra breaks, so here is the new end of my script, I know it's not perfect but right now if the scriptblock does end in 1 then it'll exit 1 without extra breaks, which Veeam does see as exit code 1.

chkdsk completed on all volumes! Logs can be found in $logs_folder."

if(Test-path $chkdskerrorlogfile -PathType leaf)
# if true do something
$Return = 1
}
else
{
# if false do something
$Return = 0
}
$Return
}
if ($ReturnCode -eq 1) {$ReturnCode = 1}
if ($ReturnCode -eq 0) {$ReturnCode = 0}
Return $ReturnCode


So above, if I change the $Return = 0 to 1, under the # if false do something, then the script will end with exit 1 and without extra breaks, if I run the script as is with $Return = 0, the scriptblock or the script itself is added 2 or 3 extra breaks at the end.
Image
https://ibb.co/XYkDFrN
Post Reply

Who is online

Users browsing this forum: Google [Bot], joast, Semrush [Bot] and 124 guests