Start Veeam SOBR job

How to start Veeam SOBR job? Note: this is for Veeam version 9.5 update 4 / 4a. If you are using a scale out repository with Veeam and have setup that repository with object cloud storage, then you may notice a SOBR tiering job. This job will periodically run every four hours.

Veeam SOBR Tiering job running

I found out that there is a Powershell command built in that will allow you to start Veeam SOBR job. It is clearly listed on Veeam’s help site.

Finally, here is the Powershell command(s) that I used to initiate a SOBR Tiering job.

Add-PSSnapin VeeamPSSnapin
$repository = Get-VBRBackupRepository -ScaleOut
Start-VBRCapacityTierSync -Repository $repository
powershell initiate SOBR tiering job

After the job runs the output looks like this:

powershell SOBR tiering job result.

Some quick notes.

  • The job will only push incremental and full backups to your capacity tier once the files are not primary in the scale out repository. These would be the ‘father’ or ‘grandfather’ tier backup files.
  • You set how long the backup files stay in the local scale out repositories in the settings for the scale out repository.
  • Even if you set the local retention for one day, the SOBR Tiering job will not necessarily offload. Veeam waits until the old backups have a separate full backup.
  • Selecting “Active Full” does not count towards the father, grandfather retention. Veeam must initiate the full backup itself based on the backup or backup copy job settings.
  • This post is intended for Veeam version 9.5 update 4 / 4a. Veeam could change the caveats and features in future releases.

Check out my previous post on Veeam here.

Find out more about Veeam and capacity tier information here.

Create PowerShell TicTacToe Game

Boredom induces the need to keep my mind busy. Imagine being stuck in a place with access to only a basic windows 10 workstation and heavily content filtered internet. Luckily, PowerShell is still enabled on the workstation. So you decide to spend your time creating a PowerShell TicTacToe game to pass the time.

Caveats and Warnings

This PowerShell TicTacToe game took me total 6 hours to research (Google search all the code formats) and put together. Warning, I tested it sparingly and I missed following basic coding best practices.

Looking back at my work there are areas of code that need to be shortened and more comments. Secondly, I prefer to consolidate code with numerous method calls instead of repeating code lines. However, for a small project that occupied my thoughts and passed the time, to small project was enjoyable.

PowerShell TicTacToe game source code

<# Tic Tac Toe Game
Created by powersjo. 
#>

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$Path = "$Home\Documents"
if(!(Test-Path -Path $Path\TicTacToe)){
    New-Item -Name TicTacToe -Path $Path -ItemType Directory    
}
if(!(Test-Path -Path $Path\TicTacToe\Board)){
    New-Item -Name Board -Path $Path\TicTacToe -ItemType Directory    
}
if(!(Test-Path -Path $Path\TicTacToe\Board\1.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 1.txt
}
if(!(Test-Path -Path $Path\TicTacToe\Board\2.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 2.txt
}
if(!(Test-Path -Path $Path\TicTacToe\Board\3.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 3.txt
}
if(!(Test-Path -Path $Path\TicTacToe\Board\4.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 4.txt
}
if(!(Test-Path -Path $Path\TicTacToe\Board\5.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 5.txt
}
if(!(Test-Path -Path $Path\TicTacToe\Board\6.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 6.txt
}
if(!(Test-Path -Path $Path\TicTacToe\Board\7.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 7.txt
}
if(!(Test-Path -Path $Path\TicTacToe\Board\8.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 8.txt
}
if(!(Test-Path -Path $Path\TicTacToe\Board\9.txt)){
    New-Item $Path\TicTacToe\Board -ItemType file -Name 9.txt
}
if(!(Test-Path -Path $Path\TicTacToe\player.txt)){
    New-Item $Path\TicTacToe -ItemType file -Name player.txt
}

Set-Content $Path\TicTacToe\player.txt '1'
Set-Content $Path\TicTacToe\Board\1.txt '0'
Set-Content $Path\TicTacToe\Board\2.txt '0'
Set-Content $Path\TicTacToe\Board\3.txt '0'
Set-Content $Path\TicTacToe\Board\4.txt '0'
Set-Content $Path\TicTacToe\Board\5.txt '0'
Set-Content $Path\TicTacToe\Board\6.txt '0'
Set-Content $Path\TicTacToe\Board\7.txt '0'
Set-Content $Path\TicTacToe\Board\8.txt '0'
Set-Content $Path\TicTacToe\Board\9.txt '0'

$Form                            = New-Object system.Windows.Forms.Form
$Form.ClientSize                 = '380,290'
$Form.text                       = "Form"
$Form.TopMost                    = $false

$Button1                         = New-Object system.Windows.Forms.Button
$Button1.text                    = ""
$Button1.width                   = 30
$Button1.height                  = 30
$Button1.location                = New-Object System.Drawing.Point(115,64)
$Button1.Font                    = 'Microsoft Sans Serif,10'

$Button2                         = New-Object system.Windows.Forms.Button
$Button2.text                    = ""
$Button2.width                   = 30
$Button2.height                  = 30
$Button2.location                = New-Object System.Drawing.Point(187,64)
$Button2.Font                    = 'Microsoft Sans Serif,10'

$Button3                         = New-Object system.Windows.Forms.Button
$Button3.text                    = ""
$Button3.width                   = 30
$Button3.height                  = 30
$Button3.location                = New-Object System.Drawing.Point(260,64)
$Button3.Font                    = 'Microsoft Sans Serif,10'

$Button4                         = New-Object system.Windows.Forms.Button
$Button4.text                    = ""
$Button4.width                   = 30
$Button4.height                  = 30
$Button4.location                = New-Object System.Drawing.Point(115,111)
$Button4.Font                    = 'Microsoft Sans Serif,10'

$Button5                         = New-Object system.Windows.Forms.Button
$Button5.text                    = ""
$Button5.width                   = 30
$Button5.height                  = 30
$Button5.location                = New-Object System.Drawing.Point(187,111)
$Button5.Font                    = 'Microsoft Sans Serif,10'

$Button6                         = New-Object system.Windows.Forms.Button
$Button6.text                    = ""
$Button6.width                   = 30
$Button6.height                  = 30
$Button6.location                = New-Object System.Drawing.Point(260,111)
$Button6.Font                    = 'Microsoft Sans Serif,10'

$Button7                         = New-Object system.Windows.Forms.Button
$Button7.text                    = ""
$Button7.width                   = 30
$Button7.height                  = 30
$Button7.location                = New-Object System.Drawing.Point(260,157)
$Button7.Font                    = 'Microsoft Sans Serif,10'

$Button8                         = New-Object system.Windows.Forms.Button
$Button8.text                    = ""
$Button8.width                   = 30
$Button8.height                  = 30
$Button8.location                = New-Object System.Drawing.Point(187,157)
$Button8.Font                    = 'Microsoft Sans Serif,10'

$Button9                         = New-Object system.Windows.Forms.Button
$Button9.text                    = ""
$Button9.width                   = 30
$Button9.height                  = 30
$Button9.location                = New-Object System.Drawing.Point(115,157)
$Button9.Font                    = 'Microsoft Sans Serif,10'

$Button10                        = New-Object system.Windows.Forms.Button
$Button10.text                   = "reset"
$Button10.width                  = 60
$Button10.height                 = 30
$Button10.location               = New-Object System.Drawing.Point(186,207)
$Button10.Font                   = 'Microsoft Sans Serif,10'

$Label1                        = New-Object System.Windows.Forms.Label
$Label1.text                   = "Turn: Player 1"
$Label1.width                  = 60
$Label1.height                 = 30
$Label1.location               = New-Object System.Drawing.Point(10,10)
$Label1.Font                   = 'Microsoft Sans Serif,10'

$Form.controls.AddRange(@($Button1,$Button2,$Button3,$Button4,$Button5,$Button6,$Button7,$Button8,$Button9,$Button10,$Label1))

$Button10.Add_Click({
    Set-Content $Path\TicTacToe\player.txt '1'
    Set-Content $Path\TicTacToe\Board\1.txt '0'
    Set-Content $Path\TicTacToe\Board\2.txt '0'
    Set-Content $Path\TicTacToe\Board\3.txt '0'
    Set-Content $Path\TicTacToe\Board\4.txt '0'
    Set-Content $Path\TicTacToe\Board\5.txt '0'
    Set-Content $Path\TicTacToe\Board\6.txt '0'
    Set-Content $Path\TicTacToe\Board\7.txt '0'
    Set-Content $Path\TicTacToe\Board\8.txt '0'
    Set-Content $Path\TicTacToe\Board\9.txt '0'
    $Button1.Text = ""
    $Button2.Text = ""
    $Button3.Text = ""
    $Button4.Text = ""
    $Button5.Text = ""
    $Button6.Text = ""
    $Button7.Text = ""
    $Button8.Text = ""
    $Button9.Text = ""
    $Label1.Text = "Turn: Player 1"
})

function Cycle-Player{
    $tempPlayer = Get-Content $Path\TicTacToe\player.txt 
    if($tempPlayer -eq 1){
        Set-Content $Path\TicTacToe\player.txt '2'
        $Label1.Text = "Turn: Player 2"
    }
    else{
        Set-Content $Path\TicTacToe\player.txt '1'
        $Label1.Text = "Turn: Player 1"
    }
}

$Button1.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\1.txt
    if($tempSpot -eq 0){
        if($tempPlayer -eq 1){
            $Button1.Text = "X"
            Set-Content $Path\TicTacToe\Board\1.txt '1'
        }
        ElseIf($tempPlayer -eq 2){
            $Button1.Text = "O"
            Set-Content $Path\TicTacToe\Board\1.txt '2'
        }
        Cycle-Player
    }
})

$Button2.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\2.txt
    if($tempSpot -eq 0){
        switch ($tempPlayer){
            1{
                $Button2.Text = "X"
                Set-Content $Path\TicTacToe\Board\2.txt '1'
            }
            2{
                $Button2.Text = "O"
                Set-Content $Path\TicTacToe\Board\2.txt '2'
            }
        }
        Cycle-Player
    }
})

$Button3.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\3.txt
    if($tempSpot -eq 0){
        switch ($tempPlayer){
            1{
                $Button3.Text = "X"
                Set-Content $Path\TicTacToe\Board\3.txt '1'
            }
            2{
                $Button3.Text = "O"
                Set-Content $Path\TicTacToe\Board\3.txt '2'
            }
        }
        Cycle-Player
    }
})

$Button4.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\4.txt
    if($tempSpot -eq 0){
        switch ($tempPlayer){
            1{
                $Button4.Text = "X"
                Set-Content $Path\TicTacToe\Board\4.txt '1'
            }
            2{
                $Button4.Text = "O"
                Set-Content $Path\TicTacToe\Board\4.txt '2'
            }
        }
        Cycle-Player
    }
})

$Button5.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\5.txt
    if($tempSpot -eq 0){
        switch ($tempPlayer){
            1{
                $Button5.Text = "X"
                Set-Content $Path\TicTacToe\Board\5.txt '1'
            }
            2{
                $Button5.Text = "O"
                Set-Content $Path\TicTacToe\Board\5.txt '2'
            }
        }
        Cycle-Player
    }
})

$Button6.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\6.txt
    if($tempSpot -eq 0){
        switch ($tempPlayer){
            1{
                $Button6.Text = "X"
                Set-Content $Path\TicTacToe\Board\6.txt '1'
            }
            2{
                $Button6.Text = "O"
                Set-Content $Path\TicTacToe\Board\6.txt '2'
            }
        }
        Cycle-Player
    }
})

$Button7.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\7.txt
    if($tempSpot -eq 0){
        switch ($tempPlayer){
            1{
                $Button7.Text = "X"
                Set-Content $Path\TicTacToe\Board\7.txt '1'
            }
            2{
                $Button7.Text = "O"
                Set-Content $Path\TicTacToe\Board\7.txt '2'
            }
        }
        Cycle-Player
    }
})

$Button8.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\8.txt
    if($tempSpot -eq 0){
        switch ($tempPlayer){
            1{
                $Button8.Text = "X"
                Set-Content $Path\TicTacToe\Board\8.txt '1'
            }
            2{
                $Button8.Text = "O"
                Set-Content $Path\TicTacToe\Board\8.txt '2'
            }
        }
        Cycle-Player
    }
})

$Button9.Add_Click({
$tempPlayer = Get-Content $Path\TicTacToe\player.txt 
$tempSpot = Get-Content $Path\TicTacToe\Board\9.txt
    if($tempSpot -eq 0){
        switch ($tempPlayer){
            1{
                $Button9.Text = "X"
                Set-Content $Path\TicTacToe\Board\9.txt '1'
            }
            2{
                $Button9.Text = "O"
                Set-Content $Path\TicTacToe\Board\9.txt '2'
            }
        }
        Cycle-Player
    }
})

$Form.ShowDialog()

In conclusion, the end product is very bare bones. The featured image above gives a screenshot of the finished product. Additionally, feel free to copy and use or improve or disregard the code. Finally, just consider the work an open source contribution to the internet. Thanks for reading.

If you want to check out my previous blog post on code / scripting click here.

If you want to read a different topic try any of my book reviews.

Most of the help I found online was located here at StackOverflow.

gpupdate and RDP with PowerShell

How to gpudate and RDP with PowerShell

In my first PowerShell post, I described running into the issue of maintaining a network where you do not have all admin permissions. A second issue that I ran into was how to gpupdate and RDP with PowerShell.  Updates were pushed out from group policy but machines were not pulling them and staying up to date. How I forced gpupdate was a lot like how I forced remote reboots with PowerShell.

for($i=0; $i -lt $WorkstationArray.Count; $i++){
     $temp = $WorkstationArray[$i]
     Write-Output "Initiate gpupdate for: " $temp
     Invoke-GPUpdate -Computer $temp
}

Loop through an array and RDP into machines

While looping through an array of the workstations it was possible that some of them would be disconnected from the network. I added code to allow me to log any workstation that I could not RDP into. I also added code to save my username and password, but you could make that more secure and not save that in your script.

$LogFile = "C:\workstation_unreachables.txt"
$User="XXXXXXXXXXXXXXX"
$Password="XXXXXXXXXXXXXXX"

Function Logfile{
    Param ([string]$logstring)
    Add-content $LogFile -value $logstring
}

for($i=0; $i -lt $ServerArray.Count; $i++){ 
    cmdkey /generic:"$Templogin" /U:$User /pass:$Password
    $temp = $ServerArray[$i] mstsc /v:"$temp" /admin 
    $log = Read-Host -Prompt "Press y to log this computer name
                   Press any other key to continue"
    if ($log -match "y"){
        LogFile "$temp"
    }
}

Run PowerShell as admin

The last item I had to do was run the PowerShell script as an administrator.  I decided to make a batch script for that. This prompted me for admin credentials whenever it was ran.

@ECHO OFF 

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""C:\gpupdate.ps1""' -Verb RunAs}"

:END
pause

I hope this helps with running gpupdate and RDP with PowerShell on your network. If you missed my first post you can read more here. Thank you – Powersjo

Most of the help I found online was located here at StackOverflow.

How to loop through AD objects with PowerShell

How to Loop through AD objects with PowerShell

While at work, I came across the problem of ‘You don’t own the network but you must deploy and administer the network’. That’s when I had the idea to employ PowerShell scripts and Batch files. When you are given tier 2 admin access to only a particular OU and not full admin access to the whole domain, these scripts might help you ensure your workstations stay up to date. How did I loop through AD objects with PowerShell?

Grab list from Active Directory

In order to loop through multiple active directory objects, I made the choice to grab all the objects in an OU and put them in a text file. To do this I ran a simple windows command in a batch file. Use the command ‘DSQUERY COMPUTER’.
For each OU, start at the top level OU and dive into the final OU.
For the Domain Controller (DC), start at your top level domain (example: blog) eventually diving into the overall domain (example: com, mil, org, us, etc…)

@echo off

DSQUERY COMPUTER "OU=TOPLEVEL,OU=MIDLEVEL,OU=LOWERLEVEL,OU=FINALLEVEL,DC=BLOG,DC=POWERSJO,DC=COM" -o rdn -limit 1000 > c:\objects.txt

pause

Using an array in PowerShell

$WorkstationArray =
''number1'', “number2”, “number3”

In the array put the list of objects from the batch file. I did this manually but I’m sure there is a way to automate it.

Loop through an array in PowerShell

for($i=0; $i -lt $WorkstationArray.Count; $i++){
$temp = $WorkstationArray[$i]
Write-Output "Initiate reboot for: " $temp
Restart-Computer -ComputerName $temp -Force
}

In the above loop I reference each workstation and initiate a restart of each one. If you use ‘-Force’, even when a user is logged in the workstation will restart.

In the next blog post I will post my method of running ‘gpupdate’, initiating RDP and running the PowerShell scripts as an administrator with batch files.