Restructured Documentation
Automatic Documentation Deployment / Sync Docs to https://kb.bunny-lab.io (push) Successful in 8s
Automatic Documentation Deployment / Sync Docs to https://kb.bunny-lab.io (push) Successful in 8s
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
---
|
||||
tags:
|
||||
- Exchange Online
|
||||
- PowerShell
|
||||
- Scripting
|
||||
---
|
||||
|
||||
## Purpose
|
||||
Sometimes you will need to connect to Office365 via powershell in order to perform troubleshooting / automation that either is too complex to do via the website, or is not exposed / possible to do via the website.
|
||||
|
||||
## Update Nuget Package Manager
|
||||
```powershell
|
||||
Install-PackageProvider -Name NuGet -Force -ForceBootstrap
|
||||
```
|
||||
|
||||
## Install ExchangeOnlineManagement Powershell Modules
|
||||
You will need to install and import the modules for Exchange Online before you can run the commands necessary for interacting with it.
|
||||
|
||||
```powershell
|
||||
Install-Module -Name ExchangeOnlineManagement -Force
|
||||
Import-Module ExchangeOnlineManagement
|
||||
```
|
||||
|
||||
## Connect to Exchange Online
|
||||
When you run the following command, it will open a dialog box to take the username, password, and MFA code (if applicable) for an administrative account in the Exchange Online environment.
|
||||
|
||||
```powershell
|
||||
Connect-ExchangeOnline -UserPrincipalName admin@domain.com
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Email Documentation](<../../../../reference/Applications/Email/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
tags:
|
||||
- Microsoft Exchange
|
||||
- Email
|
||||
---
|
||||
|
||||
## Purpose
|
||||
Sometimes you need to set an autoreply on a mailbox on behalf of someone else. In these cases, you can leverage the "Exchange Admin Shell" to configure an auto-reply to anyone who sends an email to the mailbox.
|
||||
|
||||
In the example below, replace `<username>` with the shortened username of the target user. (e.g. `nicole.rappe` not `nicole.rappe@bunny-lab.io`)
|
||||
|
||||
```powershell
|
||||
Set-MailboxAutoReplyConfiguration -Identity <username> -AutoReplyState Scheduled -StartTime "1/1/2025 00:00:00" -EndTime "1/15/2025 00:00:00" -InternalMessage "Example,<br><br>Message here.<br><br>Thank you." -ExternalMessage "Example,<br><br>Message here.<br><br>Thank you."
|
||||
```
|
||||
|
||||
!!! note "Internal vs External"
|
||||
When you configure auto-replies, you can have different replies sent to people within the same organization versus external senders, keep this in mind based on the roles of the person.
|
||||
|
||||
!!! example "Example Email Reply"
|
||||
The email auto reply will look something like this based on the command above.
|
||||
|
||||
```text
|
||||
Example,
|
||||
|
||||
Message Here.
|
||||
|
||||
Thank you.
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Email Documentation](<../../../../reference/Applications/Email/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
tags:
|
||||
- Microsoft Exchange
|
||||
- Email
|
||||
---
|
||||
|
||||
## Purpose
|
||||
Start the Microsoft Exchange and supporting Windows services selected by this PowerShell script. The script sets their startup type to Automatic, so review the service requirements for the target server before running it.
|
||||
|
||||
!!! warning "Review Service Startup Changes"
|
||||
The preserved script sets every selected service to Automatic and starts it, including services that may intentionally be disabled. It does not perform a service restart. Do not use it as the return-to-service step for Exchange SE; follow the baseline-specific service validation in the rolling-update workflow.
|
||||
|
||||
```powershell
|
||||
$servicelist = Get-Service | Where-Object {$_.DisplayName -like "Microsoft Exchange *"}
|
||||
$servicelist += Get-Service | Where-Object {$_.DisplayName -eq "IIS Admin Service"}
|
||||
$servicelist += Get-Service | Where-Object { $_.DisplayName –eq "Windows Management Instrumentation" }
|
||||
$servicelist += Get-Service | Where-Object { $_.DisplayName –eq "World Wide Web Publishing Service" }
|
||||
|
||||
foreach($service in $servicelist){
|
||||
Set-Service $service -StartupType Automatic
|
||||
Start-Service $service
|
||||
}
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Exchange SE Maintenance](<../../../../workflows/Applications/Email/Microsoft Exchange/Perform Exchange SE DAG Rolling Updates.md>) — Use its service-baseline validation when maintaining an SE DAG.
|
||||
- [Related Email Documentation](<../../../../reference/Applications/Email/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
---
|
||||
tags:
|
||||
- DFS
|
||||
- Active Directory
|
||||
- PowerShell
|
||||
---
|
||||
|
||||
## Purpose
|
||||
Report the DFS namespaces, folder targets, and replication configuration in the current Active Directory domain. Run the script in PowerShell with the DFSN and DFSR modules and permission to query the domain.
|
||||
|
||||
## Script
|
||||
You may want to put together a simple table report of the DFS namespaces, replication info, and target folders. You can run the following powershell script to generate a nice table-based report of the current structure of the DFS namespaces in your domain.
|
||||
|
||||
??? example "Powershell Reporting Script"
|
||||
|
||||
```powershell
|
||||
# Automatically detect current AD domain and use it as DFS prefix
|
||||
try {
|
||||
$Domain = ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).Name
|
||||
$DomainPrefix = "\\$Domain"
|
||||
} catch {
|
||||
Write-Warning "Unable to detect domain automatically. Falling back to manual value."
|
||||
$DomainPrefix = "\\bunny-lab.io"
|
||||
}
|
||||
|
||||
Import-Module DFSN -ErrorAction Stop
|
||||
Import-Module DFSR -ErrorAction Stop
|
||||
|
||||
function Get-ServerNameFromPath {
|
||||
param([string]$Path)
|
||||
if ([string]::IsNullOrWhiteSpace($Path)) { return $null }
|
||||
if ($Path -like "\\*") { return ($Path -split '\\')[2] }
|
||||
return $null
|
||||
}
|
||||
function Get-Max3 {
|
||||
param([int[]]$Values)
|
||||
if (-not $Values) { return 0 }
|
||||
return (($Values | Measure-Object -Maximum).Maximum)
|
||||
}
|
||||
|
||||
# Build: GroupName (lower) -> memberships[]
|
||||
$allGroups = Get-DfsReplicationGroup -ErrorAction SilentlyContinue
|
||||
$groupMembershipMap = @{}
|
||||
foreach ($g in $allGroups) {
|
||||
$ms = Get-DfsrMembership -GroupName $g.GroupName -ErrorAction SilentlyContinue
|
||||
$groupMembershipMap[$g.GroupName.ToLower()] = $ms
|
||||
}
|
||||
|
||||
# Flatten all memberships for regex fallback
|
||||
$allMemberships = @()
|
||||
foreach ($arr in $groupMembershipMap.Values) { if ($arr) { $allMemberships += $arr } }
|
||||
|
||||
$rows = New-Object System.Collections.Generic.List[psobject]
|
||||
|
||||
# Enumerate namespace roots
|
||||
$roots = Get-DfsnRoot -ErrorAction Stop | Where-Object { $_.Path -like "$DomainPrefix\*" }
|
||||
|
||||
Write-Host "DFS Namespace and Replication Overview" -ForegroundColor Cyan
|
||||
Write-Host "------------------------------------------------------`n"
|
||||
|
||||
foreach ($root in $roots) {
|
||||
|
||||
$rootPath = $root.Path
|
||||
$rootLeaf = ($rootPath -split '\\')[-1]
|
||||
|
||||
$nsServers = @()
|
||||
$rootTargets = Get-DfsnRootTarget -Path $rootPath -ErrorAction SilentlyContinue
|
||||
foreach ($rt in $rootTargets) {
|
||||
$srv = Get-ServerNameFromPath $rt.TargetPath
|
||||
if ($srv) { $nsServers += $srv }
|
||||
}
|
||||
|
||||
# Folders under this root
|
||||
$folders = Get-DfsnFolder -Path "$rootPath\*" -ErrorAction SilentlyContinue | Sort-Object Path
|
||||
|
||||
foreach ($f in $folders) {
|
||||
$namespaceFull = $f.Path
|
||||
$leaf = ($f.Path -split '\\')[-1]
|
||||
|
||||
# DFSN folder targets
|
||||
$targets = Get-DfsnFolderTarget -Path $f.Path -ErrorAction SilentlyContinue
|
||||
$targets = @($targets | Sort-Object { Get-ServerNameFromPath $_.TargetPath }) # ensure array
|
||||
|
||||
# Map to DFSR group by naming; fallback to regex on ContentPath
|
||||
$candidateGroup = ((($rootPath -replace '^\\\\','') + '\' + $leaf).ToLower())
|
||||
if ($groupMembershipMap.ContainsKey($candidateGroup)) {
|
||||
$msForFolder = $groupMembershipMap[$candidateGroup]
|
||||
} else {
|
||||
$escapedRootLeaf = [regex]::Escape($rootLeaf)
|
||||
$escapedLeaf = [regex]::Escape($leaf)
|
||||
$regex = "\\$escapedRootLeaf\\$escapedLeaf($|\\)"
|
||||
$msForFolder = $allMemberships | Where-Object { $_.ContentPath -imatch $regex }
|
||||
}
|
||||
$msForFolder = @($msForFolder) # normalize to array
|
||||
|
||||
# Build aligned rows: one per target
|
||||
$targetLines = @()
|
||||
$replLines = @()
|
||||
|
||||
foreach ($t in $targets) {
|
||||
$tServer = Get-ServerNameFromPath $t.TargetPath
|
||||
$targetLines += $t.TargetPath
|
||||
|
||||
$msForServer = $null
|
||||
if ($msForFolder.Count -gt 0) {
|
||||
$msForServer = $msForFolder | Where-Object { $_.ComputerName -ieq $tServer } | Select-Object -First 1
|
||||
}
|
||||
if ($msForServer -and $msForServer.ContentPath) { $replLines += $msForServer.ContentPath } else { $replLines += '' }
|
||||
}
|
||||
|
||||
# Max line count for row expansion (PS 5.1 safe)
|
||||
$maxLines = Get-Max3 @($targetLines.Count, $replLines.Count, $nsServers.Count)
|
||||
|
||||
for ($i = 0; $i -lt $maxLines; $i++) {
|
||||
|
||||
# Precompute values (PS 5.1: no inline-if in hashtables)
|
||||
$nsVal = ''
|
||||
if ($i -eq 0) { $nsVal = $namespaceFull }
|
||||
|
||||
$targetVal = ''
|
||||
if ($i -lt $targetLines.Count) { $targetVal = $targetLines[$i] }
|
||||
|
||||
$replVal = ''
|
||||
if ($i -lt $replLines.Count) { $replVal = $replLines[$i] }
|
||||
|
||||
$nsServerVal = ''
|
||||
if ($i -lt $nsServers.Count) { $nsServerVal = $nsServers[$i] }
|
||||
|
||||
$row = [PSCustomObject]@{
|
||||
'Namespace' = $nsVal
|
||||
'Member Folder Target(s)' = $targetVal
|
||||
'Replication Locations' = $replVal
|
||||
'Namespace Servers' = $nsServerVal
|
||||
}
|
||||
$rows.Add($row) | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Render as a PowerShell bordered grid with one-space left/right padding in every cell
|
||||
function Write-DfsGrid {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Collections.IEnumerable]$Data,
|
||||
|
||||
[string[]]$Columns = @('Namespace','Member Folder Target(s)','Replication Locations','Namespace Servers'),
|
||||
|
||||
# Reasonable max widths; tune to your console (these are content+padding widths)
|
||||
[int[]]$MaxWidths = @(70, 70, 52, 30),
|
||||
|
||||
[switch]$Ascii # use +-| instead of box-drawing if your console garbles Unicode
|
||||
)
|
||||
|
||||
# Ensure arrays align
|
||||
if ($MaxWidths.Count -lt $Columns.Count) {
|
||||
$pad = New-Object System.Collections.Generic.List[int]
|
||||
$pad.AddRange($MaxWidths)
|
||||
for ($i=$MaxWidths.Count; $i -lt $Columns.Count; $i++) { $pad.Add(40) }
|
||||
$MaxWidths = $pad.ToArray()
|
||||
}
|
||||
|
||||
# Characters
|
||||
if ($Ascii) {
|
||||
$H = @{ tl='+'; tr='+'; bl='+'; br='+'; hz='-'; vt='|'; tj='+'; mj='+'; bj='+' }
|
||||
} else {
|
||||
# Box-drawing
|
||||
$H = @{ tl='┌'; tr='┐'; bl='└'; br='┘'; hz='─'; vt='│'; tj='┬'; mj='┼'; bj='┴' }
|
||||
try { [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8 } catch {}
|
||||
}
|
||||
|
||||
function TruncPad([string]$s, [int]$w) {
|
||||
if ($null -eq $s) { $s = '' }
|
||||
$s = $s -replace '\r','' -replace '\t',' '
|
||||
if ($s.Length -le $w) { return $s.PadRight($w, ' ') }
|
||||
if ($w -le 1) { return $s.Substring(0, $w) }
|
||||
return ($s.Substring(0, $w-1) + '…')
|
||||
}
|
||||
|
||||
# Materialize and compute widths (include one-space left/right padding for header and data)
|
||||
$rows = @($Data | ForEach-Object {
|
||||
$o = @{}
|
||||
foreach ($c in $Columns) { $o[$c] = [string]($_.$c) }
|
||||
[pscustomobject]$o
|
||||
})
|
||||
|
||||
$widths = @()
|
||||
for ($i=0; $i -lt $Columns.Count; $i++) {
|
||||
$col = $Columns[$i]
|
||||
# Start with header length including padding
|
||||
$max = (" " + $col + " ").Length
|
||||
foreach ($r in $rows) {
|
||||
$len = (" " + [string]$r.$col + " ").Length
|
||||
if ($len -gt $max) { $max = $len }
|
||||
}
|
||||
$widths += [Math]::Min($max, $MaxWidths[$i])
|
||||
}
|
||||
|
||||
# Line builders
|
||||
function DrawTop() {
|
||||
$line = $H.tl
|
||||
for ($i = 0; $i -lt $widths.Count; $i++) {
|
||||
$line += ($H.hz * $widths[$i])
|
||||
if ($i -lt ($widths.Count - 1)) {
|
||||
$line += $H.tj
|
||||
} else {
|
||||
$line += $H.tr
|
||||
}
|
||||
}
|
||||
$line
|
||||
}
|
||||
function DrawMid([string[]]$Columns, [int[]]$widths, $H) {
|
||||
$line = $H.vt
|
||||
for ($i=0; $i -lt $widths.Count; $i++) {
|
||||
$line += TruncPad (" " + $Columns[$i] + " ") $widths[$i]
|
||||
$line += $H.vt
|
||||
}
|
||||
$line
|
||||
}
|
||||
function DrawSep() {
|
||||
$line = $H.vt
|
||||
for ($i=0; $i -lt $widths.Count; $i++) {
|
||||
$line += ($H.hz * $widths[$i])
|
||||
$line += $H.vt
|
||||
}
|
||||
$line
|
||||
}
|
||||
function DrawHeaderSep() {
|
||||
$line = $H.vt
|
||||
for ($i=0; $i -lt $widths.Count; $i++) {
|
||||
$line += ($H.hz * $widths[$i])
|
||||
$line += $H.vt
|
||||
}
|
||||
$line
|
||||
}
|
||||
function DrawBottom() {
|
||||
$line = $H.bl
|
||||
for ($i = 0; $i -lt $widths.Count; $i++) {
|
||||
$line += ($H.hz * $widths[$i])
|
||||
if ($i -lt ($widths.Count - 1)) {
|
||||
$line += $H.bj
|
||||
} else {
|
||||
$line += $H.br
|
||||
}
|
||||
}
|
||||
$line
|
||||
}
|
||||
function DrawRow($r, [string[]]$Columns, [int[]]$widths, $H) {
|
||||
$line = $H.vt
|
||||
for ($i=0; $i -lt $widths.Count; $i++) {
|
||||
$val = [string]$r.($Columns[$i])
|
||||
$line += TruncPad (" " + $val + " ") $widths[$i]
|
||||
$line += $H.vt
|
||||
}
|
||||
$line
|
||||
}
|
||||
|
||||
# Render with group separators between namespaces (when the Namespace cell is non-empty)
|
||||
Write-Host (DrawTop)
|
||||
Write-Host (DrawMid -Columns $Columns -widths $widths -H $H)
|
||||
Write-Host (DrawHeaderSep)
|
||||
|
||||
$first = $true
|
||||
foreach ($r in $rows) {
|
||||
if (-not $first -and ([string]$r.$($Columns[0])) ) {
|
||||
# Namespace changed → draw a separator
|
||||
Write-Host (DrawSep)
|
||||
}
|
||||
$first = $false
|
||||
Write-Host (DrawRow -r $r -Columns $Columns -widths $widths -H $H)
|
||||
}
|
||||
|
||||
Write-Host (DrawBottom)
|
||||
}
|
||||
|
||||
Write-DfsGrid -Data $rows
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [DFS Deployment](<../../../../deployments/Applications/Files and Collaboration/Windows Server/DFS Namespaces with Replication.md>) — Review the namespace and replication structure that this report inspects.
|
||||
- [Related Files and Collaboration Documentation](<../../../../reference/Applications/Files and Collaboration/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,132 @@
|
||||
---
|
||||
tags:
|
||||
- DFS
|
||||
- Replication
|
||||
- PowerShell
|
||||
---
|
||||
|
||||
## Purpose
|
||||
Report the directional replication backlog between the DFS member servers in the script. Set the member names to the intended deployment and run from a PowerShell session with access to its DFS replication configuration.
|
||||
|
||||
## Script
|
||||
You may want to check that replication is occurring bi-directionally between every member server in your DFS deployment. I wrote a script below that effectively shows you every replication group and each directional backlog status.
|
||||
|
||||
```powershell
|
||||
# --- CONFIG ---
|
||||
$Members = @("LAB-FPS-01","LAB-FPS-02")
|
||||
$SummarizeAcrossFolders = $true # $true = one line per direction per RG; $false = per-folder lines
|
||||
|
||||
function Invoke-DfsrBacklogStatus {
|
||||
param(
|
||||
[Parameter(Mandatory)] [string] $RG,
|
||||
[Parameter(Mandatory)] [string] $RF,
|
||||
[Parameter(Mandatory)] [string] $Send,
|
||||
[Parameter(Mandatory)] [string] $Recv
|
||||
)
|
||||
|
||||
$out = & dfsrdiag backlog /rgname:"$RG" /rfname:"$RF" /sendingmember:"$Send" /receivingmember:"$Recv" 2>&1 | Out-String
|
||||
$outTrim = ($out -split "`r?`n" | ForEach-Object { $_.Trim() }) | Where-Object { $_ -ne "" }
|
||||
|
||||
if ($out -match 'No Backlog') {
|
||||
return [pscustomobject]@{ Status="No Backlog"; Count=0; Detail=$null }
|
||||
}
|
||||
|
||||
$count = $null
|
||||
$countLine = $outTrim | Where-Object { $_ -match '(?i)backlog' } | Select-Object -First 1
|
||||
if ($countLine -and ($countLine -match '(\d+)')) { $count = [int]$matches[1] }
|
||||
|
||||
$detail = ($outTrim | Select-Object -First 8) -join " | "
|
||||
|
||||
return [pscustomobject]@{
|
||||
Status = if ($count -ne $null) { "Backlog: $count" } else { "Backlog/Check Output" }
|
||||
Count = $count
|
||||
Detail = $detail
|
||||
}
|
||||
}
|
||||
|
||||
$groups = Get-DfsReplicationGroup | Sort-Object GroupName
|
||||
|
||||
foreach ($g in $groups) {
|
||||
$rg = $g.GroupName
|
||||
$rfs = Get-DfsReplicatedFolder -GroupName $rg | Sort-Object FolderName
|
||||
|
||||
Write-Host ""
|
||||
Write-Host ("== Replication Group: {0} ==" -f $rg)
|
||||
|
||||
foreach ($send in $Members) {
|
||||
foreach ($recv in $Members) {
|
||||
if ($send -eq $recv) { continue }
|
||||
|
||||
if ($SummarizeAcrossFolders) {
|
||||
$worstCount = 0
|
||||
$nonZero = @()
|
||||
$errorsOrDetails = @()
|
||||
|
||||
foreach ($rfObj in $rfs) {
|
||||
$rf = $rfObj.FolderName
|
||||
$res = Invoke-DfsrBacklogStatus -RG $rg -RF $rf -Send $send -Recv $recv
|
||||
|
||||
if ($res.Status -ne "No Backlog") {
|
||||
$nonZero += [pscustomobject]@{ RF=$rf; Status=$res.Status; Count=$res.Count; Detail=$res.Detail }
|
||||
if ($res.Count -ne $null -and $res.Count -gt $worstCount) { $worstCount = $res.Count }
|
||||
|
||||
# ✅ FIX: ${rf} avoids the ':' parsing issue
|
||||
if ($res.Detail) { $errorsOrDetails += "RF=${rf}: $($res.Detail)" }
|
||||
}
|
||||
}
|
||||
|
||||
if ($nonZero.Count -eq 0) {
|
||||
Write-Host ("{0} -> {1}: No Backlog" -f $send, $recv)
|
||||
} else {
|
||||
if ($worstCount -gt 0) {
|
||||
Write-Host ("{0} -> {1}: Backlog (max {2} across RFs)" -f $send, $recv, $worstCount)
|
||||
} else {
|
||||
Write-Host ("{0} -> {1}: Backlog/Errors (see details)" -f $send, $recv)
|
||||
}
|
||||
|
||||
$errorsOrDetails | Select-Object -First 5 | ForEach-Object { Write-Host (" - {0}" -f $_) }
|
||||
if ($errorsOrDetails.Count -gt 5) { Write-Host " - ... (more omitted)" }
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach ($rfObj in $rfs) {
|
||||
$rf = $rfObj.FolderName
|
||||
$res = Invoke-DfsrBacklogStatus -RG $rg -RF $rf -Send $send -Recv $recv
|
||||
|
||||
if ($res.Status -eq "No Backlog") {
|
||||
Write-Host ("{0} -> {1} [{2}]: No Backlog" -f $send, $recv, $rf)
|
||||
} else {
|
||||
Write-Host ("{0} -> {1} [{2}]: {3}" -f $send, $recv, $rf, $res.Status)
|
||||
if ($res.Detail) { Write-Host (" - {0}" -f $res.Detail) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! example "Example Output"
|
||||
You will see output like the following when you run the script.
|
||||
|
||||
```powershell
|
||||
== Replication Group: bunny-lab.io\music\fl studio plugins ==
|
||||
LAB-FPS-01 -> LAB-FPS-02: No Backlog
|
||||
LAB-FPS-02 -> LAB-FPS-01: No Backlog
|
||||
|
||||
== Replication Group: bunny-lab.io\music\personal music ==
|
||||
LAB-FPS-01 -> LAB-FPS-02: No Backlog
|
||||
LAB-FPS-02 -> LAB-FPS-01: No Backlog
|
||||
|
||||
== Replication Group: bunny-lab.io\music\shared music ==
|
||||
LAB-FPS-01 -> LAB-FPS-02: No Backlog
|
||||
LAB-FPS-02 -> LAB-FPS-01: No Backlog
|
||||
|
||||
== Replication Group: bunny-lab.io\projects\coding ==
|
||||
LAB-FPS-01 -> LAB-FPS-02: No Backlog
|
||||
LAB-FPS-02 -> LAB-FPS-01: No Backlog
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [DFS Deployment](<../../../../deployments/Applications/Files and Collaboration/Windows Server/DFS Namespaces with Replication.md>) — Identify the replication members and folders.
|
||||
- [Related Files and Collaboration Documentation](<../../../../reference/Applications/Files and Collaboration/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
tags:
|
||||
- PowerShell
|
||||
- Scripting
|
||||
---
|
||||
|
||||
## Purpose
|
||||
Sometimes you just need a basic script that outputs a pretty directory and file tree. This script offers files and folders to ignore, and outputs a fancy directory tree.
|
||||
|
||||
```powershell
|
||||
function Export-Tree {
|
||||
param (
|
||||
[string]$Path = ".",
|
||||
[string]$OutFile = "directory_tree.txt"
|
||||
)
|
||||
|
||||
$global:TreeLines = @()
|
||||
$global:IgnoreList = @(
|
||||
".git",
|
||||
"Dependencies"
|
||||
)
|
||||
|
||||
function Walk-Tree {
|
||||
param (
|
||||
[string]$Folder,
|
||||
[string]$Prefix
|
||||
)
|
||||
|
||||
$items = Get-ChildItem -Path $Folder -Force | Where-Object {
|
||||
$_.Name -ne "." -and $_.Name -ne ".." -and
|
||||
($global:IgnoreList -notcontains $_.Name)
|
||||
} | Sort-Object PSIsContainer, Name
|
||||
|
||||
$count = $items.Count
|
||||
|
||||
for ($i = 0; $i -lt $count; $i++) {
|
||||
$item = $items[$i]
|
||||
$connector = if ($i -eq $count - 1) { "└── " } else { "├── " }
|
||||
$global:TreeLines += "$Prefix$connector$($item.Name)"
|
||||
if ($item.PSIsContainer) {
|
||||
$newPrefix = if ($i -eq $count - 1) { "$Prefix " } else { "$Prefix│ " }
|
||||
Walk-Tree -Folder $item.FullName -Prefix $newPrefix
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Walk-Tree -Folder $Path -Prefix ""
|
||||
|
||||
$global:TreeLines | Set-Content -Path $OutFile -Encoding UTF8
|
||||
}
|
||||
|
||||
# Run it
|
||||
Export-Tree -Path "." -OutFile "directory_tree.txt"
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Files and Collaboration Documentation](<../../../reference/Applications/Files and Collaboration/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
tags:
|
||||
- PowerShell
|
||||
- File Management
|
||||
- Scripting
|
||||
---
|
||||
|
||||
## Purpose
|
||||
Locate specific files, and copy them with a renamed datestamp appended to a specific directory.
|
||||
|
||||
```powershell
|
||||
# Define an array of objects, each having a prefix and a suffix
|
||||
$files = @(
|
||||
@{Prefix="name"; Suffix="Extension"},
|
||||
@{Prefix="name"; Suffix="Extension"}
|
||||
)
|
||||
|
||||
# Define the destination directory
|
||||
$destination = "C:\folder\to\copy\to"
|
||||
|
||||
# Loop over the file name patterns
|
||||
foreach ($file in $files) {
|
||||
# Search for files that start with the current prefix and end with the current suffix
|
||||
$matches = Get-ChildItem -Path C:\ -Recurse -ErrorAction SilentlyContinue -Filter "$($file.Prefix)*.$($file.Suffix)"
|
||||
|
||||
# Loop over the matching files
|
||||
foreach ($match in $matches) {
|
||||
# Get the file's last modified date
|
||||
$lastModifiedDate = $match.LastWriteTime
|
||||
|
||||
# Get the file's owner
|
||||
$owner = (Get-Acl -Path $match.FullName).Owner
|
||||
|
||||
# Output the file name, last modified date, and owner
|
||||
Write-Output "File: $($match.FullName), Last Modified Date: $lastModifiedDate, Owner: $owner"
|
||||
|
||||
# Generate a unique name for the copied file by appending the last modified date and time
|
||||
$newName = "{0}_{1:yyyyMMdd_HHmmss}{2}" -f $match.BaseName, $lastModifiedDate, $match.Extension
|
||||
|
||||
# Copy the file to the destination directory with the new name
|
||||
Copy-Item -Path $match.FullName -Destination (Join-Path -Path $destination -ChildPath $newName)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Files and Collaboration Documentation](<../../../reference/Applications/Files and Collaboration/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
---
|
||||
tags:
|
||||
- SMB
|
||||
- PowerShell
|
||||
- Permissions
|
||||
- Scripting
|
||||
---
|
||||
|
||||
## Purpose
|
||||
This script will iterate over all network shares hosted by the computer it is running on, and will give *recursive* permissions to all folders, subfolders, and files, including hidden ones. It is very I/O intensive given it iterates recursively on every file/folder being shared.
|
||||
|
||||
```powershell
|
||||
$AllShares = Get-SMBShare | Where-Object {$_.Description -NotMatch "Default share|Remote Admin|Remote IPC|Printer Drivers"} | Select-Object -ExpandProperty Path
|
||||
$Output = @()
|
||||
ForEach ($SMBDirectory in $AllShares)
|
||||
{
|
||||
$FolderPath = Get-ChildItem -Directory -Path $SMBDirectory -Recurse -Force
|
||||
ForEach ($Folder in $FolderPath) {
|
||||
$Acl = Get-Acl -Path $Folder.FullName
|
||||
ForEach ($Access in $Acl.Access)
|
||||
{
|
||||
$Properties = [ordered]@{'Folder Name'=$Folder.FullName;'Group/User'=$Access.IdentityReference;'Permissions'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
|
||||
$Output += New-Object -TypeName PSObject -Property $Properties
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$Output | Export-CSV -Path C:\SMB_REPORT.csv -NoTypeInformation -Append
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Files and Collaboration Documentation](<../../../../reference/Applications/Files and Collaboration/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
tags:
|
||||
- SMB
|
||||
- PowerShell
|
||||
- Permissions
|
||||
- Scripting
|
||||
---
|
||||
|
||||
## Purpose
|
||||
This script will iterate over all network shares hosted by the computer it is running on, and will give *top-level* permissions to all the shared folders. It will not navigate deeper than the top-level in its report. Very I/O friendly.
|
||||
|
||||
```powershell
|
||||
$AllShares = Get-SMBShare | Where-Object {$_.Description -NotMatch "Default share|Remote Admin|Remote IPC|Printer Drivers"} | Select-Object -ExpandProperty Name
|
||||
ForEach ($SMBDirectory in $AllShares)
|
||||
{
|
||||
Get-SMBShareAccess -Name $SMBDirectory | Export-CSV -Path C:\SMB_REPORT.csv -NoTypeInformation -Append
|
||||
}
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Files and Collaboration Documentation](<../../../../reference/Applications/Files and Collaboration/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,160 @@
|
||||
---
|
||||
tags:
|
||||
- Nextcloud
|
||||
- PowerShell
|
||||
- Scripting
|
||||
---
|
||||
|
||||
## Purpose
|
||||
In some unique cases, you want to be able to either perform backups of data or exfiltrate data to Nextcloud from a local device via the use of a script. Doing such a thing with Nextcloud as the destination is not very documented, but you can achieve that result by running a script like what is seen below:
|
||||
|
||||
## Windows
|
||||
!!! abstract "Environment Variables"
|
||||
You will need to assign the following variables either within the script or externally via environment variables at the time the script is executed.
|
||||
|
||||
| **Variable** | **Default Value** | **Description** |
|
||||
| :--- | :--- | :--- |
|
||||
| `NEXTCLOUD_SERVER_URL` | `https://cloud.bunny-lab.io` | This is the base URL of the Nextcloud server that data will be copied to. |
|
||||
| `NEXTCLOUD_SHARE_PASSWORD` | `<Share Password>` | You need to create a share on Nextcloud, and configure it as a `File Drop`, then put a share password to protect it. Put that password here. |
|
||||
| `NEXTCLOUD_SHARE` | `ABCDEFGHIJK` | The tail-end of a nextcloud share link, e.g. `https://cloud.bunny-lab.io/s/<<ABCDEFGHIJK>>` |
|
||||
| `IGNORE_LIST` | `AppData;AMD;Drivers;Radeon;Program Files;Program Files (x86);Windows;$SysReset;$WinREAgent;PerfLogs;ProgramData;Recovery;System Volume Information;hiberfile.sys;pagefile.sys;swapfile.sys` | This is a list of files/folders to ignore when iterating through directories. A sensible default is selected if you choose to copy everything from the root C:\ directory. |
|
||||
| `PRIMARY_DIR` | `C:\Users\Example` | This directory target is the primary focus of the upload / backup / exfiltration. The script will iterate through this target first before it moves onto the secondary target. The target can be a directory or a single file. This will act as the main priority of the transfer. |
|
||||
| `SECONDARY_DIR` | `C:\` | This is the secondary target, it's less important but nice-to-have with the upload / backup / exfiltration once the primary copy is completed. The target can be a directory or a single file. |
|
||||
| `LOGFILE` | `C:\Windows\Temp\nc_pull.log` | This file is how the script has "persistence". In case the computer is shut down, rebooted, etc, when it comes back online and the script is re-ran against it, it reads this file to pick up where it last was, and attempts to resume from that point. If this transfer is meant to be hidden, put this file somewhere someone is not likely to find it easily. |
|
||||
|
||||
### Powershell Script
|
||||
```powershell
|
||||
# --------------------------
|
||||
# Function for File Upload Logic
|
||||
# --------------------------
|
||||
Function Upload-Files ($targetDir) {
|
||||
Get-ChildItem -Path $targetDir -Recurse -File -Force -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
try {
|
||||
# --------------------------
|
||||
# Check Ignore List
|
||||
# --------------------------
|
||||
$ignore = $false # Initialize variable to check if current folder should be ignored
|
||||
foreach ($item in $IGNORE_LIST) {
|
||||
if ($_.Directory -match [regex]::Escape($item)) {
|
||||
$ignore = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($ignore) {
|
||||
Write-Host "Ignoring file $($_.FullName) due to directory match in ignore list."
|
||||
return
|
||||
}
|
||||
|
||||
# --------------------------
|
||||
# Upload File Process
|
||||
# --------------------------
|
||||
$filename = $_.Name # Extract just the filename
|
||||
|
||||
# Check if this file has been uploaded before by searching in the log file
|
||||
if ((Get-Content $LOGFILE) -notcontains $_.FullName) {
|
||||
|
||||
Write-Host "Uploading $($_.FullName) ..."
|
||||
|
||||
# Upload the file
|
||||
$response = Invoke-RestMethod -Uri ($URL + $filename) -Method Put -InFile $_.FullName -Headers @{'X-Requested-With' = 'XMLHttpRequest'} -Credential $credentials
|
||||
|
||||
# Record this file in the log since it was successfully uploaded
|
||||
Add-Content -Path $LOGFILE -Value $_.FullName
|
||||
|
||||
} else {
|
||||
Write-Host "Skipping previously uploaded file $($_.FullName)"
|
||||
}
|
||||
} catch {
|
||||
Write-Host "Error encountered while processing $($_.FullName): $_.Exception.Message"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --------------------------
|
||||
# Initialize Environment Variables
|
||||
# --------------------------
|
||||
$securePassword = ConvertTo-SecureString $env:NEXTCLOUD_SHARE_PASSWORD -AsPlainText -Force
|
||||
$credentials = New-Object System.Management.Automation.PSCredential ($env:NEXTCLOUD_SHARE, $securePassword)
|
||||
$PRIMARY_DIR = $env:PRIMARY_DIR
|
||||
$SECONDARY_DIR = $env:SECONDARY_DIR
|
||||
$URL = "$env:NEXTCLOUD_SERVER_URL/public.php/webdav/"
|
||||
$IGNORE_LIST = $env:IGNORE_LIST -split ';' # Splitting the folder names into an array
|
||||
|
||||
# --------------------------
|
||||
# Checking Log File
|
||||
# --------------------------
|
||||
if (-not (Test-Path $LOGFILE)) {
|
||||
New-Item -Path $LOGFILE -ItemType "file"
|
||||
}
|
||||
|
||||
# --------------------------
|
||||
# Perform Uploads
|
||||
# --------------------------
|
||||
Write-Host "Uploading files from primary directory: $PRIMARY_DIR"
|
||||
Upload-Files $PRIMARY_DIR
|
||||
|
||||
Write-Host "Uploading files from secondary directory: $SECONDARY_DIR"
|
||||
Upload-Files $SECONDARY_DIR
|
||||
|
||||
```
|
||||
|
||||
## MacOS/Linux
|
||||
!!! abstract "Environment Variables"
|
||||
You will need to assign the following variables either within the script or externally via environment variables at the time the script is executed.
|
||||
|
||||
| **Variable** | **Default Value** | **Description** |
|
||||
| :--- | :--- | :--- |
|
||||
| `NEXTCLOUD_SERVER_URL` | `https://cloud.bunny-lab.io` | This is the base URL of the Nextcloud server that data will be copied to. |
|
||||
| `NEXTCLOUD_SHARE_PASSWORD` | `<Share Password>` | You need to create a share on Nextcloud, and configure it as a `File Drop`, then put a share password to protect it. Put that password here. |
|
||||
| `NEXTCLOUD_SHARE` | `ABCDEFGHIJK` | The tail-end of a nextcloud share link, e.g. `https://cloud.bunny-lab.io/s/<<ABCDEFGHIJK>>` |
|
||||
| `DATA_TO_COPY` | `/home/bunny/example` | This directory target is the primary focus of the upload / backup / exfiltration. The script will iterate through this target first before it moves onto the secondary target. The target can be a directory or a single file. This will act as the main priority of the transfer. |
|
||||
| `LOGFILE` | `/tmp/uploaded_files.log` | This file is how the script has "persistence". In case the computer is shut down, rebooted, etc, when it comes back online and the script is re-ran against it, it reads this file to pick up where it last was, and attempts to resume from that point. If this transfer is meant to be hidden, put this file somewhere someone is not likely to find it easily. |
|
||||
|
||||
### Bash Script
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# Directory to search
|
||||
DIR=$DATA_TO_COPY
|
||||
|
||||
# URL for the upload
|
||||
URL="$NEXTCLOUD_SERVER_URL/public.php/webdav/"
|
||||
|
||||
# Check if log file exists. If not, create one.
|
||||
if [ ! -f "$LOGFILE" ]; then
|
||||
touch "$LOGFILE"
|
||||
fi
|
||||
|
||||
# Iterate over each file in the directory and its subdirectories
|
||||
find "$DIR" -type f -print0 | while IFS= read -r -d '' file; do
|
||||
# Extract just the filename
|
||||
filename=$(basename "$file")
|
||||
|
||||
# Check if this file has been uploaded before
|
||||
if ! grep -q "$file" "$LOGFILE"; then
|
||||
echo "Uploading $file ..."
|
||||
|
||||
# Upload the file
|
||||
response=$(curl -k -s -T "$file" -u "$NEXTCLOUD_SHARE:$NEXTCLOUD_SHARE_PASSWORD" -H 'X-Requested-With: XMLHttpRequest' "$URL$filename")
|
||||
|
||||
# Get the HTTP status code
|
||||
status_code=$(curl -s -o /dev/null -w ''%{http_code}'' "$URL$filename")
|
||||
|
||||
# # Print the HTTP status code
|
||||
# echo "HTTP status code: $status_code"
|
||||
|
||||
# # Check the HTTP status code
|
||||
# if [[ "$status_code" = "200" ]]; then
|
||||
# # If upload was successful, record this file in the log
|
||||
echo "$file" >> "$LOGFILE"
|
||||
# else
|
||||
# echo "Failed to upload $file"
|
||||
# fi
|
||||
else
|
||||
echo "Skipping previously uploaded file $file"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Files and Collaboration Documentation](<../../../reference/Applications/Files and Collaboration/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,165 @@
|
||||
---
|
||||
tags:
|
||||
- Minecraft
|
||||
- PowerShell
|
||||
- Scripting
|
||||
---
|
||||
|
||||
## Purpose
|
||||
This script was purpose-built for the homelab Minecraft servers in my homelab. It may need to be ported based on your own needs.
|
||||
|
||||
```powershell
|
||||
clear
|
||||
|
||||
# #################################################
|
||||
# # BUNNY LAB - MINECRAFT UPGRADE SCRIPT #
|
||||
# #################################################
|
||||
|
||||
# Function to display the banner
|
||||
function Show-Banner {
|
||||
Write-Host "#################################################" -ForegroundColor Cyan
|
||||
Write-Host "# BUNNY LAB - MINECRAFT UPGRADE SCRIPT #" -ForegroundColor Cyan
|
||||
Write-Host "#################################################" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# Function to get user input for the zip file
|
||||
function Get-ZipFileName {
|
||||
Write-Host "Step 1: Getting the zip file name from user input..." -ForegroundColor Yellow
|
||||
Write-Host "Please enter the name of the newest Minecraft ZIP file in the downloads folder (e.g., 'Server-Files-x.xx.zip'): " -ForegroundColor Yellow
|
||||
$zipFileName = Read-Host
|
||||
$zipFilePath = "C:\Users\nicole.rappe\Downloads\$zipFileName"
|
||||
|
||||
# Check if the zip file exists in the Downloads folder
|
||||
Write-Host "Verifying if the specified ZIP file exists at: $zipFilePath" -ForegroundColor Yellow
|
||||
if (-not (Test-Path $zipFilePath)) {
|
||||
Write-Host "File not found! Please check the file name and try again." -ForegroundColor Red
|
||||
exit
|
||||
}
|
||||
|
||||
Write-Host "ZIP file found: $zipFilePath" -ForegroundColor Green
|
||||
return $zipFilePath
|
||||
}
|
||||
|
||||
# Function to unzip the file without nesting
|
||||
function Unzip-ServerFiles {
|
||||
param (
|
||||
[string]$zipFilePath,
|
||||
[string]$destinationFolder
|
||||
)
|
||||
|
||||
Write-Host "Step 2: Unzipping the server files to: $destinationFolder" -ForegroundColor Yellow
|
||||
|
||||
# Create a temporary folder for extraction
|
||||
$tempFolder = "$env:TEMP\MinecraftTemp"
|
||||
Write-Host "Creating temporary folder for extraction at: $tempFolder" -ForegroundColor Yellow
|
||||
|
||||
# Remove the temporary folder if it exists, then recreate it
|
||||
if (Test-Path $tempFolder) {
|
||||
Write-Host "Temporary folder exists. Removing existing folder..." -ForegroundColor Yellow
|
||||
Remove-Item -Recurse -Force $tempFolder
|
||||
}
|
||||
New-Item -ItemType Directory -Path $tempFolder
|
||||
|
||||
Write-Host "Unzipping new server files..." -ForegroundColor Green
|
||||
Expand-Archive -Path $zipFilePath -DestinationPath $tempFolder -Force
|
||||
|
||||
Write-Host "Moving unzipped files to destination folder: $destinationFolder" -ForegroundColor Green
|
||||
# Move the contents of the temporary folder to the destination
|
||||
Get-ChildItem -Path $tempFolder -Recurse | Move-Item -Destination $destinationFolder -Force
|
||||
|
||||
# Clean up the temporary folder
|
||||
Write-Host "Cleaning up temporary folder..." -ForegroundColor Yellow
|
||||
Remove-Item -Recurse -Force $tempFolder
|
||||
}
|
||||
|
||||
# Function to copy specific files/folders from the old deployment
|
||||
function Copy-ServerData {
|
||||
param (
|
||||
[string]$sourceFolder,
|
||||
[string]$destinationFolder
|
||||
)
|
||||
|
||||
Write-Host "Step 3: Copying server data from: $sourceFolder to: $destinationFolder" -ForegroundColor Yellow
|
||||
|
||||
# Files to copy
|
||||
Write-Host "Copying essential files..." -ForegroundColor Yellow
|
||||
Copy-Item "$sourceFolder\eula.txt" "$destinationFolder\eula.txt" -Force
|
||||
Copy-Item "$sourceFolder\user_jvm_args.txt" "$destinationFolder\user_jvm_args.txt" -Force
|
||||
Copy-Item "$sourceFolder\ops.json" "$destinationFolder\ops.json" -Force
|
||||
Copy-Item "$sourceFolder\server.properties" "$destinationFolder\server.properties" -Force
|
||||
# Copy-Item "$sourceFolder\mods\ftbbackups2-neoforge-1.21-1.0.28.jar" "$destinationFolder\mods\ftbbackups2-neoforge-1.21-1.0.28.jar" -Force
|
||||
Copy-Item "$sourceFolder\config\ftbbackups2.json" "$destinationFolder\config\ftbbackups2.json" -Force
|
||||
|
||||
Write-Host "Copying world data and backups folder..." -ForegroundColor Yellow
|
||||
# Folder to copy (recursively)
|
||||
Copy-Item "$sourceFolder\world" "$destinationFolder\world" -Recurse -Force
|
||||
# New-Item -ItemType SymbolicLink -Path "\backups" -Target "Z:\"
|
||||
}
|
||||
|
||||
# Function to rename the old folder with the current date
|
||||
function Rename-OldServer {
|
||||
param (
|
||||
[string]$oldFolderPath
|
||||
)
|
||||
|
||||
$currentDate = Get-Date -Format "MM-dd-yyyy"
|
||||
$backupFolderPath = "$oldFolderPath.backup.$currentDate"
|
||||
|
||||
Write-Host "Step 4: Renaming old server folder to: $backupFolderPath" -ForegroundColor Yellow
|
||||
Rename-Item -Path $oldFolderPath -NewName $backupFolderPath
|
||||
Write-Host "Old server folder renamed to: $backupFolderPath" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Function to rename the new deployment to 'ATM10'
|
||||
function Rename-NewServer {
|
||||
param (
|
||||
[string]$newDeploymentPath,
|
||||
[string]$finalServerPath
|
||||
)
|
||||
|
||||
Write-Host "Step 5: Renaming new deployment folder to 'ATM10' at: $finalServerPath" -ForegroundColor Yellow
|
||||
Rename-Item -Path $newDeploymentPath -NewName $finalServerPath
|
||||
Write-Host "New server folder renamed to 'ATM10' at: $finalServerPath" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Main Script Logic
|
||||
|
||||
# Show banner
|
||||
Show-Banner
|
||||
|
||||
# Variables for folder paths
|
||||
$oldServerFolder = "C:\Users\nicole.rappe\Desktop\Minecraft_Server\ATM10"
|
||||
$newDeploymentFolder = "C:\Users\nicole.rappe\Desktop\Minecraft_Server\ATM10_NewDeployment"
|
||||
$finalServerFolder = "C:\Users\nicole.rappe\Desktop\Minecraft_Server\ATM10"
|
||||
|
||||
# Step 1: Get the zip file name from the user
|
||||
$zipFilePath = Get-ZipFileName
|
||||
|
||||
# Step 2: Unzip the file to the new deployment folder without nesting
|
||||
Unzip-ServerFiles -zipFilePath $zipFilePath -destinationFolder $newDeploymentFolder
|
||||
|
||||
# Step 3: Copy necessary files/folders from the old server
|
||||
Copy-ServerData -sourceFolder $oldServerFolder -destinationFolder $newDeploymentFolder
|
||||
|
||||
# Step 4: Rename the old server folder with the current date
|
||||
Rename-OldServer -oldFolderPath $oldServerFolder
|
||||
|
||||
# Step 5: Rename the new deployment folder to 'ATM10'
|
||||
Rename-NewServer -newDeploymentPath $newDeploymentFolder -finalServerPath $finalServerFolder
|
||||
|
||||
# Step 6. Create Symbolic Link to Backup Drive
|
||||
Write-Host "Step 6: Create Symbolic Link to Backup Drive" -ForegroundColor Cyan
|
||||
cd "C:\Users\nicole.rappe\Desktop\Minecraft_Server\ATM10"
|
||||
cmd.exe /c mklink /D backups Z:\
|
||||
|
||||
# Step 7: Notify the user that the server is ready to launch
|
||||
Write-Host "Step 7: Server Ready to Launch!" -ForegroundColor Cyan
|
||||
|
||||
Write-Host "Press any key to exit the script"
|
||||
[System.Console]::ReadKey($true) # Waits for a key press and doesn't display the pressed key
|
||||
|
||||
clear
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Applications Documentation](<../../../reference/Applications/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
tags:
|
||||
- Blue Iris
|
||||
- Batch
|
||||
- Monitoring
|
||||
- Scripting
|
||||
- Windows
|
||||
---
|
||||
|
||||
## Purpose
|
||||
This document records the procedure for blue iris server watchdog. Follow the environment assumptions and commands below.
|
||||
|
||||
```batch
|
||||
@echo off
|
||||
|
||||
REM Change to the Blue Iris 5 directory
|
||||
CD "C:\Program Files\Blue Iris 5"
|
||||
|
||||
:LOOP
|
||||
REM Check if the BlueIrisAdmin.exe process is running
|
||||
tasklist /FI "IMAGENAME eq BlueIris.exe" | find /I "BlueIris.exe" >nul
|
||||
|
||||
REM If the process is not found, start the process
|
||||
if errorlevel 1 (
|
||||
REM Start BlueIrisAdmin.exe
|
||||
BlueIrisAdmin.exe
|
||||
)
|
||||
|
||||
REM Wait for 10 seconds before checking again
|
||||
timeout /t 10 /nobreak >nul
|
||||
|
||||
REM Go back to the beginning of the loop
|
||||
GOTO :LOOP
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
- [Related Applications Documentation](<../../../reference/Applications/index.md>) — Find the connected deployments, procedures, and references for this subject.
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
tags:
|
||||
- Applications
|
||||
- Scripts
|
||||
- Documentation
|
||||
---
|
||||
|
||||
# Applications
|
||||
## Purpose
|
||||
Find scripts for applications. Follow the subject guide to choose the relevant environment and connect this material to the other document types.
|
||||
|
||||
## Includes
|
||||
- Email
|
||||
- Files and Collaboration
|
||||
- Gaming and Media
|
||||
- Home Automation
|
||||
|
||||
## Follow the Subject
|
||||
[Applications](<../../reference/Applications/index.md>) explains the relationships and offers starting points for the documented tasks.
|
||||
Reference in New Issue
Block a user