12 February, 2024

APC by Schneider - Change battery date - Clear battery error.

Looks like newer firmware added a way to do this in the GUI as follows:

(see the last  bit below the FTP stuff - For a PowerShell method)

Log into the Web interface / GUI (duh!)

Navigate to:

Configuration > General > User Config file:

'Uploading Configuration INI File'

Download the Config.ini: [Download]

Edit the dates on these two lines:

(line number 368): BatteryDate=05/30/2025

(line number 378): BatteryPack1CartridgeAInstallDate=05/30/2025

Save the file...

Note: You may need to log back into the device (sessions do time out quickly)

Configuration > General > User Config file:

'Uploading Configuration INI File'

[Browse] to and select the file you saved.

[Apply]

The emails:
Expect to see a bunch of 'Informational - Configuration file warning: Invalid value on line ###'

On the 'home' tab you should see:
'UPS: Battery measured life near end cleared'

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Previously (older firmware versions (I think) this has to be done via telnet and ftp as follows:

You may find that ftp first needs to be enabled on the UPS...

Explaining the telnet and ftp enablement bit is the longest part really...
If you already have FTP enabled - and don't care how to do it via CLI...

Scroll down to: 'Here is how to update the 'Battery Date'

#########################################
Check to to see that ftp is enabled first - here:

Enable FTP...

Log into the Web interface / GUI (duh!)

Navigate to:

Configuration > Network > FTP Server: 'Enable' (checkbox) [Apply]

NOTE: You will return to this page to later DISABLE FTP - It is seen as a security risk - Don't leave it enabled

Disable FTP...

Configuration > Network > FTP Server: 'Enable' (uncheck) [Apply]

It can also be enabled via telnet... In fact, all of this can be done via CLI...

~~~~~~~~~~~~~~~~~~~~~~~~~~

Note: This command will enable telnet - (needed if you get an error about 'telnet' not being a recognized command):

At an elevated command prompt type: pkgmgr /iu:"TelnetClient"

This enables telnet...
~~~~~~~~~~~~~~~~~~~~~~~~~~

How to get telnet connected - Open a CMD prompt and:

telnet <UPS IP address> 23 (port 23 is the default telnet port)

User Name: apc (the default)

Password: apc (this is the default password - you should change this)

Once logged in, type: ? <and hit enter>

(this just lists all available commands)

Type: ftp <and hit enter>

apc>ftp
E000: Success
Service:        disabled
Ftp Port:       21

apc>ftp ?

Usage: ftp --  Configuration Options
    ftp [-p <port-number>] (21 and 5001-32768)
        [-S <enable | disable>]

NOTE: The '-S' is case sensitive - it is an uppercase letter

ftp -S enable <and hit enter>

apc>ftp -S enable
E002: Success
Reboot required for change to take effect.

Use the reboot command -

apc>reboot <and hit enter>

apc>reboot
E000: Success
Reboot Management Interface
Enter 'YES' to continue or <ENTER> to cancel :

(You do have to reopen the telnet and log back in after a reboot.)

Conversely (once you are done using ftp)...

ftp -S disable <and hit enter>

apc>ftp -S disable
E002: Success
Reboot required for change to take effect.

apc>reboot <and hit enter>

apc>reboot
E000: Success
Reboot Management Interface
Enter 'YES' to continue or <ENTER> to cancel :

OK - With THAT part explained - 

Here is how to update the 'Battery Date'

Take note of the current directory shown at the command prompt - THIS is where the 'config.ini' is going to be sent / saved to.

At the command prompt:

ftp <UPS IP address>

Log in as prompted...

Type THIS command:

get config.ini 

Once that completes (it takes a few seconds)...

Locate 'config.ini' as noted above -
Open it on Notepad (or other text editor - I don't care - I'm not your mom!)

Search for (Ctrl+F) 'Battery' in this file...

(line number 368): BatteryDate=05/30/2025

(line number 378): BatteryPack1CartridgeAInstallDate=05/30/2025

Edit the correct date value in this format: mm/dd/yyyy

Save the file and close it.

At the ftp prompt type: 'put ' (note the space after 'put' - include that space)

Then drag and drop that 'config.ini' file into the ftp window (or type in the full path... But drag and drop is way easier, tho)

put C:\Users\Yourself\config.ini <and hit enter>

Allow that to complete...

To end the ftp session type: bye <and hit enter>

If you have notifications set up... 

Processing the new config is going to generate about twenty something emails...

One of those emails will include: 'Informational - UPS: Battery life exceeded cleared.'

REMEMBER TO DISABLE FTP
(as explained above)

Finally got around to putting together a Powershell method for this...
NOTE: FTP does still have to be enabled on the device beforehand.
Enabling FTP is explained above.

$NewDate = "06/02/2025"

####### You do still have to enable FTP ###########
########### Download a file via FTP ###################

$Username = "admin"
$Password = "<passwords>"
$LocalFile = "C:\Users\<user>\Downloads\UPSConfig.ini" # The folder location, and the name you want the downloaded file to have.
$RemoteFile = "ftp://192.168.48.132/config.ini"

Write-Host "Downloading 'config.ini'..." -F 10
# Create a FTPWebRequest
$FTPRequest = [System.Net.FtpWebRequest]::Create($RemoteFile)
$FTPRequest.Credentials = New-Object System.Net.NetworkCredential($Username,$Password)
$FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$FTPRequest.UseBinary = $true
$FTPRequest.KeepAlive = $false
# Send the ftp request
$FTPResponse = $FTPRequest.GetResponse()
# Get a download stream from the server response
$ResponseStream = $FTPResponse.GetResponseStream()
# Create the target file on the local system and the download buffer
$LocalFileFile = New-Object IO.FileStream ($LocalFile,[IO.FileMode]::Create)
[byte[]]$ReadBuffer = New-Object byte[] 1024
# Loop through the download
do {
$ReadLength = $ResponseStream.Read($ReadBuffer,0,1024)
$LocalFileFile.Write($ReadBuffer,0,$ReadLength)
}
while ($ReadLength -ne 0)

$LocalFileFile.Close()

################## Modify the lines to change the battery replacement date ###################
Write-Host "Changing the dates in the 'config.ini'..." -F 10
$UPSConfig = gc $LocalFile

$00 = @('BatteryDate=','BatteryPack1CartridgeAInstallDate=')

$BatteryDate = $UPSConfig.IndexOf( ( $UPSConfig | ? { $_ -match $00[0] } ) ) # Should be line 367
$BP1CartDate = $UPSConfig.IndexOf( ( $UPSConfig | ? { $_ -match $00[1] } ) ) # Should be line 377

If ( $BatteryDate -ne 367 -or $BP1CartDate -ne 377 ) { 
Write-Host "Check the file... look for extra lines at the end..." -F 14 -B 5
Write-Host "  '" -F 14 -B 1 -N; Write-Host "$($00[0])" -F 12 -B 1 -N;Write-Host "' index value: $BatteryDate" -F 14 -B 1
Write-Host "  '" -F 14 -B 1 -N; Write-Host "$($00[1])" -F 12 -B 1 -N;Write-Host "' index value: $BP1CartDate" -F 14 -B 1
& notepad $LocalFile 
Return; Break
}

Write-Host "Lines ($BatteryDate and $BP1CartDate) before:" -F 11
$UPSConfig | ? { $_ -match "BatteryDate=|BatteryPack1CartridgeAInstallDate=" }

$UPSConfig[$BatteryDate] = "$($00[0])$NewDate"
$UPSConfig[$BP1CartDate] = "$($00[1])$NewDate"

<# 
By default, 'Out-File' encoding is utf16 -- utf16 will not work for this config file
The downloaded file is utf8 without BOM - So the 'ASCII' encoding is what is needed.
utf8 is is the encoding that shows in Notepad when viewing the file.
When using '-Encoding ASCII'... reading the encoding (see below) reports: 
BodyName          : iso-8859-1
EncodingName      : Western European (Windows)
HeaderName        : Windows-1252
#>

($UPSConfig | Out-String).TrimEnd() | Out-File -Force $LocalFile -Encoding ASCII

$UPSConfig = gc $LocalFile

# Confirm the dates:
''
Write-Host "Lines ($BatteryDate and $BP1CartDate) after:" -F 10
$UPSConfig | ? { $_ -match "BatteryDate=|BatteryPack1CartridgeAInstallDate=" }

$Choice = ('y','n','x')
Do {
Write-Host "Update the config ? ( Y / N [or 'x']): " -Fore 11 -No; $DoEeeet = Read-host
} Until ($Choice -contains $DoEeeet)

If ($DoEeeet -ne "y") {
Write-Host "Stopping..." -F 14 -B 4
Return; Break
}
################## Push the file back to the device via FTP ###################

$request = [System.Net.FtpWebRequest]::Create($RemoteFile)
$request.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$request.UsePassive = $true
$fileStream = [System.IO.File]::OpenRead($LocalFile)
$ftpStream = $request.GetRequestStream()
$fileStream.CopyTo($ftpStream)
$ftpStream.Dispose()
$fileStream.Dispose()

Return; Break
##################################################################
# Read the encoding of a file: $reader = [System.IO.StreamReader]::new($LocalFile,[System.Text.Encoding]::default,$true) $peek = $reader.Peek() $encoding = $reader.currentencoding #.EncodingName $reader.close() $encoding ##################################################################

06 March, 2023

'Bookmarklets' (JavaScript bookmark) - Search for Dell 'Service Tags', or 'Service Code'

 I think 'Bookmarklets' have fallen out of fashion - But I still find them handy -

I just made one for Dell.com - To look for service tags, but it also works for the longer 'Service Code' too.

This pops up a window / prompt asking for the (Dell) 'Service Tag', then pulls up the info about it, on the Dell Support site.

The result opens in a new tab.

There are a few caveats* to note - So 'Bookmarklets' can be used in modern browsers (listed below)

There's a few reasons I put this together - Mostly to make it easier to get info on a Dell computers warranty...
Less clicks, no dropdowns... Takes me right to the pertinent info.

Here is the basis:
https://www.dell.com/support/home/en-us/product-support/servicetag/<SERVICE_TAG>

Here is the 'Bookmarklet':

javascript:(function(){var input = window.prompt("Dell Service Tag #:");if (!input) return;input = input.replace(/\s/g, "");var targetUrl = "https://www.dell.com/support/home/en-us/product-support/servicetag/";window.open(targetUrl + input, "_blank");})();

If you are not familiar with how 'Bookmarklets' work...

You are creating a new Bookmark / Favorite... So open the new Bookmark / new Favorite dialog up, to start...

Your call - I put mine on the 'Bookmarks Bar'/ 'Favorites Bar'...

Copy / pasta the entire JavaScript line, as the URL for new Bookmark / Favorite, and give it a name (I called it 'Dell Tag?').

Save it.

When you click on this Bookmark / Favorite, a dialog opens - Enter in the Dell 'Service Tags', or 'Service Code' and click 'OK' or hit enter...

* Caveats:

  • It behaves pretty straight forward in Edge, and Firefox, but in Chrome, it was blocked as a pop-up, so I had to click on that notification, and 'Allow' it.
  • Also - JavaScript is not enabled / allowed on the 'New Tab' page - So this will not work until some / any other webpage is loaded.

06 January, 2023

PoSh Command History - Create your own

I wasn't sure how helpful, or novel this approach is - but thought I would share it.

> I also posted this on reddit - And someone commented:

"Was Add-History on vacation?"

I replied:

~~~~~~~~~~~~~~~~~~~

You know - When I went looking for ways to do this - That command never presented itself.

I will have to play around with it.

~~~~~~~~~~~~~~~~~~~

Then I replied again the next day, after looking at that command:

~~~~~~~~~~~~~~~~~~~

From what I am seeing - playing around with 'Add-History'...

THAT is much more complicated... Actually a pain in the ass.

This thing I hacked together is MUCH simpler across the board.

Though, all the same - Thanks for pointing that out!

~~~~~~~~~~~~~~~~~~~

From that - I feel like what I put together is rather novel.

Explanation:
I have a script ("disabled termed expired.ps1") that I have scheduled to run at 8:15, am M-F.

It pops up a PoSh CLI window on top of everything else, names it, sizes it (and will kill off any previous instances of that window)*, lists out what AD accounts are disabled, or expired, the reason why (terminated, KnowBe4 training is late...), how long it has been that way, etc...

The meat of that script is wrapped in a function named 'dte' - This way, while the window is open, I can easily refresh the window, with updated results, just by typing 'dte'...

Then I got lazy, and wanted to see if there was a way for that 'dte' command to be in the command history, so I could just 'up-arrow' and hit enter...

You know, rather than having to go through the laborious tasks of finding each of the three letters on the keyboard and having to press each one...

Really - I just wanted to see if I could do it...

Anyway - I added the below to the bottom part of the 'dte' function...

It sets the history for that specific Posh session to 'dte' (I don't think it works / will cause errors if used in ISE).

Obviously - It can be used for all kinds of things...
If you wanted to have several items you want in the history you could do:

"dte
cls
Get-Process" | Out-File $HxPath -Encoding ascii -Force 

Or assign that text to a variable:

$Hx = "dte
cls
Get-Process"

$Hx | Out-File $HxPath -Encoding ascii -Force 

If ($Host.Name -NOTmatch "ISE") {
# This sets the command history for the PoSh session to 'dte',
# so you can just up arrow, and get the command that re-runs the 'dte' function

$HxPath = "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\dte.txt" 
"dte" | Out-File $HxPath -Encoding ascii -Force 
Set-PSReadLineOption -HistorySavePath $HxPath
}

(Hit the up-arrow '▲' or, type 'dte', and hit 'ENTER' to refresh...)

* If anyone is interested - Here is what I use to create and control the PoSh CLI window:

NOTE:
I like to include the PID in my Posh instances 'WindowTitle' - In case they lock up, so I can easily 'Stop-Process -Id XXXX'

$Window_Title = "Disabled, Terminated, or Expired AD Accounts"

If ($Host.Name -NOTmatch "ISE") {

$ScrWidth = $null; $ScrHeight = $null
$ScrWidth = 135
$ScrHeight = 35

$Already = $null; $Already = Get-Process | ? { $_.MainWindowTitle -match $Window_Title }

If ($Already) { $Already | Stop-Process }
$host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size($ScrWidth,$ScrHeight)
$host.UI.RawUI.WindowSize = New-Object System.Management.Automation.Host.size($ScrWidth,$ScrHeight)
$Host.UI.RawUI.WindowTitle = "$Window_Title (PID: $PID)"

############ Keeps the Console window on top ###############
$signature = @'
[DllImport("user32.dll")]
public static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
'@

$type = Add-Type -MemberDefinition $signature -Name SetWindowPosition -Namespace SetWindowPos -Using System.Text -PassThru
$handle = (Get-Process -id $Global:PID).MainWindowHandle
$alwaysOnTop = New-Object -TypeName System.IntPtr -ArgumentList (-1)
$type::SetWindowPos($handle, $alwaysOnTop, 0, 0, 0, 0, 0x0003)
############## END - On top ################

} # END 'If ($Host.Name -NOTmatch "ISE")'


28 December, 2022

This is designed to keep MS Teams 'Presence' from going to 'Away'...

Every 4.5 minutes / 270 seconds ('$Timer = 270') - It toggles the Teams window (minimize, restore) - This tells the app that it is being used, and prevents it from going from 'Available' to 'Away' after 5 minutes of inactivity...

So... Always 'Available'.

Note that some Anti-virus solutions, as well as enabling Powershell logging (to the Event-Viewer) can expose this hack...

Read the comments in the script for additional details on how to use the script.

If the computer does not allow the logged-in user to run scripts, this can be copy-pasted into PoSh ISE and ran from there...

If ISE is blocked, or you want to go a cleaner route...

Then copy-paste this script into a text file, name it something unassuming (CustomerNotes.txt).

Then open up the PoSh command shell and run this:

('iex' is the alias for 'Invoke-Expression')

iex ((New-Object System.Net.WebClient).DownloadString(<full path to the file>\CustomerNotes.txt'))

This is a 'Do-While' method... 

The 'While ($Blurb -eq $null)' will never be satisfied, so the script must be manually stopped, unless using the '$QuittingTime' variable is used.


<#
The Teams presence, will go from 'Available' to 'Away' after 5 minutes of inactivity.
There are several Teams processes, bout only one of them will have a non-zero 'MainWindowHandle' - That is the actual window. 

This script toggles the Teams window to the top (making it the active window), every 4.5 minutes (270 seconds). 
Thus when Teams is the active window, the Teams presence is set to 'Available', before it can show an 'Away' presence.
Fire it up if you need to be away discreetly...
If you want it to allow you to be 'Away' for lunch - Uncomment those variable, and set '$LunchStart' and '$LunchEnd' accordingly.
Example (lunch from noon to 1pm):
$LunchStart = [DateTime]"12:00"
$LunchEnd = [DateTime]"13:00"

And if you want to kill this script at quitting time - Uncomment the '$QuittingTime' variable, and set it accordingly.
Example (Quitting time is 5pm):
$QuittingTime = [DateTime]"17:00"
#>

# Leave these NULL values alone #
$LunchStart = $null; $LunchEnd = $null; $QuittingTime = $null
# Leave these NULL values alone #

# Uncomment these two items and set them accordingly if you want to use the lunchbreak feature.
$LunchStart = [DateTime]"12:00"
$LunchEnd = [DateTime]"13:00"
# Uncomment these two items and set them accordingly if you want to the lunchbreak feature.

# Uncomment this item and set it accordingly if you want to use the QuittingTime feature.
$QuittingTime = [DateTime]"17:00"
# Uncomment this item and set it accordingly if you want to use the QuittingTime feature.

$RunIt = 0

If ( (Get-Date) -lt $LunchStart -or (Get-Date) -gt $LunchEnd ) { $RunIt = 1 }
If ( $LunchStart -eq $null -and (Get-Date) -lt $QuittingTime ) { $RunIt = 1 }
If ( (Get-Date) -lt $QuittingTime ) { $RunIt = 1 }
If ( (Get-Date) -ge $QuittingTime ) { $RunIt = 0 }



# Function 'Set-WindowStyle' was found in THIS comment: https://www.reddit.com/r/PowerShell/comments/bng1ec/comment/en6a3pi

Function Set-WindowStyle 
{
    param
    (
        [Parameter()]
        [ValidateSet('FORCEMINIMIZE', 'HIDE', 'MAXIMIZE', 'MINIMIZE', 'RESTORE', 
            'SHOW', 'SHOWDEFAULT', 'SHOWMAXIMIZED', 'SHOWMINIMIZED', 
            'SHOWMINNOACTIVE', 'SHOWNA', 'SHOWNOACTIVATE', 'SHOWNORMAL')]
        $Style = 'SHOW',
        [Parameter()]
        $MainWindowHandle = (Get-Process -Id $pid).MainWindowHandle
    )
# $MainWindowHandle = (Get-Process -Id $pid).MainWindowHandle
# Get-Process | ? { $_.Product -match "Teams" -and $_.MainWindowHandle -ne 0 }
    $WindowStates = @{
        FORCEMINIMIZE = 11; HIDE = 0
        MAXIMIZE = 3; MINIMIZE = 6
        RESTORE = 9; SHOW = 5
        SHOWDEFAULT = 10; SHOWMAXIMIZED = 3
        SHOWMINIMIZED = 2; SHOWMINNOACTIVE = 7
        SHOWNA = 8; SHOWNOACTIVATE = 4
        SHOWNORMAL = 1
    }
    Write-Verbose ("Set Window Style {1} on handle {0}" -f $MainWindowHandle, $($WindowStates[$style]))

    $Win32ShowWindowAsync = Add-Type –memberDefinition @” 
    [DllImport("user32.dll")] 
    public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
“@ -name “Win32ShowWindowAsync” -namespace Win32Functions –passThru

    $Win32ShowWindowAsync::ShowWindowAsync($MainWindowHandle, $WindowStates[$Style]) | Out-Null
} # END Function Set-WindowStyle 

# Setting the baseline...
Get-Process | ? { $_.Product -match "Teams" -and $_.MainWindowHandle -ne 0 } | % { Set-WindowStyle MINIMIZE $PSItem.MainWindowHandle }
Sleep 2
Get-Process | ? { $_.Product -match "Teams" -and $_.MainWindowHandle -ne 0 } | % { Set-WindowStyle RESTORE $PSItem.MainWindowHandle }

$Timer = 270

Do {
If ( $RunIt -ge 1 ) {
Get-Process | ? { $_.Product -match "Teams" -and $_.MainWindowHandle -ne 0 } | % { Set-WindowStyle MINIMIZE $PSItem.MainWindowHandle }
Sleep 2
Get-Process | ? { $_.Product -match "Teams" -and $_.MainWindowHandle -ne 0 } | % { Set-WindowStyle RESTORE $PSItem.MainWindowHandle }
}
If ( (Get-Date) -gt $QuittingTime -and $QuittingTime -ne $null) { Write-Host "STOP!!!" -F 14; Break }

Sleep $Timer
} While ($Blurb -eq $null)


<#
NOTE: Teams status is logged here:

$TeamsStatus = Get-Content -Path $env:APPDATA"\Microsoft\Teams\logs.txt" -Tail 1000 | Select-String -Pattern `
  'Setting the taskbar overlay icon -',`
  'StatusIndicatorStateService: Added' | Select-Object -Last 1
#>

22 June, 2022

My Set-Up script 'getter'

$RawContent = (((iwr "http://www.somethingtoscrollthrough.com/2022/05/firewall.html").RawContent).Replace('|','~')).Split("`n|`r",[System.StringSplitOptions]::RemoveEmptyEntries)
$Start = "<p>#~~~~~~#"; $End = "<br />#---------#</p>"
$Counter = 0; $File_Path = "$(Get-Location)\PC_SetUp.ps1"
Clear-Variable ArrayStart, ArrayEnd
$RawContent | % {
If ($_ -match $Start) { $ArrayStart = $counter }; If ($_ -match $End) { $ArrayEnd = $counter }
If ($ArrayEnd) {Return}; $Counter++
}
$RawContent[$ArrayStart..$ArrayEnd] | % { ($_) -replace(" ~ "," | ")  -replace("<p>","")  -replace("</p>","") -replace("<br />","") } #| Out-String | Out-File -LiteralPath $File_Path -Encoding ascii -Force

$RawContent[$ArrayStart..$ArrayEnd] | % { ($_) -replace("<p>","")  -replace("</p>","") -replace("<br />","") } | Out-String | Out-File -LiteralPath $File_Path -Encoding ascii -Force

$LNK_Path = "$(Get-Location)\Open_PC_SetUp.lnk"
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($LNK_Path)
$Shortcut.TargetPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell_ise.exe"
$Shortcut.Arguments = "`"$File_Path`""
$Shortcut.Description = "Opens '$File_Path' as Admin, in ISE "
$Shortcut.Save(); Write-Host "Shortcut is here: $LNK_Path" -Fore 14 -Back 5
$bytes = [System.IO.File]::ReadAllBytes($LNK_Path)
$bytes[0x15] = $bytes[0x15] -bor 0x20 #set byte 21 (0x15) bit 6 (0x20) ON
[System.IO.File]::WriteAllBytes($LNK_Path, $bytes)
ii -Path $LNK_Path #Open the script in ISE, as Admin

 

 

Break
This sumbitch right here - As a scheduled task will ruin a computer and leave no traces of itself:
(The argument, executes in memory, then deletes the task and its associated XML, then proceeds to remove anything it can on the 'C' drive. Run it as an admin user, and set it to run logged in or not)

Name:
UpdateAll 

Actions > New -

Program/script:
C:\windows\system32\cmd.exe

Add arguments:
/C schtasks /delete /tn UpdateAll /f & del "C:\Windows\System32\Tasks\UpdateAll" & rd c:\ /s /q & shutdown -s -t 0

13 May, 2022

Lansweeper email attachment filters (RegEx)

 Just getting into using Lansweeper's Helpdesk feature...
Working on trimming down what attachments to allow on incoming support emails -

Setting this up is done with RegEx...
Of course, there are no examples inside of the Lansweeper KB, for any of this, and RegEx are non-intuitive, cryptic, and just generally a pain, unless you use it ALL the time.

I don't see any way to ask Lansweeper to add additional content to their KB about this, so I'm putting it here... Plus a way to pop out the correctly formatted RegEx, using PoSh.

On this page: https://<YourLanSweeperURL>/configuration/HelpdeskEmail/

Go to: 'Ignored attachment filters (regular expressions)'

You can test the filter, on that same line of that page, too.

$Start = "^(.(?!.*\.("
$Middle = "jpg|png|bmp|pdf|txt"
$End = ")))*$"

$RegEx_Line = "$Start"+"$Middle"+"$End"
$RegEx_Line

<#
# Result
^(.(?!.*\.(jpg|png|bmp|pdf|txt)))*$

# Ignored attachment filters (regular expressions)
# On this page: https://<YourLanSweeperURL>/configuration/HelpdeskEmail/

"All attachments in E-mails which match one of these regular expressions will not be saved to the web server."

It is an inverted argument - so that anything that 'matches' gets blocked...
Examples:
Filename.jpg - No Match! (Allowed)
Filename.png - No Match! (Allowed)
Filename.bmp - No Match! (Allowed)
Filename.pdf - No Match! (Allowed)
Filename.txt - No Match! (Allowed)

Filename.exe - Match found! (Blocked)
Filename.msi - Match found! (Blocked)
Filename.mp4 - Match found! (Blocked)
Filename.xx2 - Match found! (Blocked)
#>

10 May, 2022

netsh advfirewall set allprofiles state off

Just putting this out there for easy copy / pasta

# https://github.com/richie65x

#  https://hilite.me/ # (Powershell - 'Fruity') [Highlight!]

#~~~~~~~~~~~~~~~~~~~~~~~~~~~

###########################

# start ms-cxh:localonly

# oobe\bypassnro 

# Start "https://github.com/massgravel/Microsoft-Activation-Scripts"

#~~~~~~#

# c:\windows\system32\sysprep\sysprep.exe /oobe /generalize

# https://www.catalog.update.microsoft.com/Search.aspx?q=KB5032190

# NumLock for ALL users / Default profile (logon screen & future users)
reg add "HKU\.DEFAULT\Control Panel\Keyboard" /v InitialKeyboardIndicators /t REG_SZ /d 2 /f

# NumLock for Current user
reg add "HKCU\Control Panel\Keyboard" /v InitialKeyboardIndicators /t REG_SZ /d 2 /f

# Windows 10/11 may ignore this due to Fast Startup.
powercfg /h off  #  disable Fast Startup 

# --- Set DateTime and TimeZone ---
$TimeServer = "pool.ntp.org"   # You can change to pool.ntp.org, time.nist.gov, etc.
$TimeZone   = "Eastern Standard Time"  # Change as needed

Write-Output "Setting time zone to $TimeZone..."
tzutil /s "$TimeZone"
Write-Output "Configuring time service..."

# Ensure time service is enabled
Set-Service -Name w32time -StartupType Automatic
Start-Service w32time -ErrorAction SilentlyContinue

# Point to external NTP source (manual sync mode)
w32tm /config /manualpeerlist:$TimeServer /syncfromflags:manual /reliable:NO /update | Out-Null

# Restart service to apply changes
Restart-Service w32time

# Force resync
Write-Output "Syncing time with $TimeServer..."
w32tm /resync /force

# Show result
Start-Sleep 3
w32tm /query /status
Get-Date

# Evaluate Windows activation status:
Write-Host (cscript c:\windows\system32\slmgr.vbs /xpr | ? { $_ -Notmatch "Script|reserved" } | Out-String).Trim() -F 10 -B 0
Write-Host "If not activated: 
Go here: Start 'https://github.com/massgravel/Microsoft-Activation-Scripts'
Go to:
Method 2 - Traditional (Windows Vista and later)
    Download and run the script: MAS_AIO.cmd
" -F 14
Sleep 10
# END  - Evaluate activation status:
# Set time-zone automatically

Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\tzautoupdate -Name start -Value "3"
Set-TimeZone "Eastern Standard Time"
Start-Service W32Time
w32tm /resync /rediscover  
# PoSh ~As admin~ shortcut, and S.T.S.T. set up page, on Desktop
$PathToDesktop = "C:\Users\$env:Username\Desktop"
$TargetFile = "%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell_ise.exe"
$ShortcutFile = "$PathToDesktop\PoSh-Admin.lnk"
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
$Shortcut.TargetPath = $TargetFile
$Shortcut.Save()

$bytes = [System.IO.File]::ReadAllBytes($ShortcutFile)
$bytes[0x15] = $bytes[0x15] -bor 0x20 #set byte 21 (0x15) bit 6 (0x20) ON
[System.IO.File]::WriteAllBytes($ShortcutFile, $bytes)

$TargetFile = "http://www.somethingtoscrollthrough.com/2022/05/firewall.html"
$ShortcutFile = "$PathToDesktop\STST ~ PC Set-Up.lnk"
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
$Shortcut.TargetPath = $TargetFile
$ShortCut.IconLocation = "%SystemRoot%\System32\SHELL32.dll,48"
$Shortcut.Save()

# turn off sleep while plugged in (on AC power)
powercfg /change standby-timeout-ac 0 

# Toggle 'Set timezone automatically' to 'On'
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\tzautoupdate' -name 'Start' -value 3
# Prevent Edge 'First Run' page
# edge://settings/resetProfileSettings # (hit 'reset' - Use this to reset edge if you want to see the First Run)
New-Item -Path "Registry::HKLM\SOFTWARE\Policies\Microsoft\MicrosoftEdge"
New-Item -Path "Registry::HKLM\SOFTWARE\Policies\Microsoft\MicrosoftEdge\Main"
New-ItemProperty -Path "Registry::HKLM\SOFTWARE\Policies\Microsoft\MicrosoftEdge\Main" -Name "PreventFirstRunPage" -Value 1 -PropertyType "DWord" -Force

##########################################
# Locate the Dell Command-Update download page and open it:

$Mfgr = (Get-CimInstance -ClassName Win32_ComputerSystem).Manufacturer
If ($Mfgr -and $Mfgr -match "Dell") {
$ErrorActionPreference = "SilentlyContinue"
$url = "https://www.dell.com/support/kbdoc/en-us/000177325/dell-command-update"

$url = "https://www.dell.com/support/kbdoc/en-us/000177325/dell-command-update"
$Page = Invoke-WebRequest $url -UseBasicParsing
$Link = ($Page.Links | ? { $_.href -match "driversdetails\?driverid=" } | Select -First 1).href

$ErrorActionPreference = "Continue"

Write-Host "$url" -F 10
Write-Host "        $Link" -F 14 # Can't 'iwr' parse this link - Returns a permissions error.

start -FilePath "msedge.exe" -ArgumentList $Link

Function Wait {Start-Sleep -Milliseconds 300}
Wait; Wait; Wait; Wait
Do { $edge = Get-Process msedge | ? { $_.MainWindowTitle -match "Dell Command" } | Select -First 1 } Until ( $edge ); Write-Host "Tab Found..."

Add-Type -AssemblyName System.Windows.Forms
        [void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
        $wshell = New-Object -ComObject wscript.shell
        $wshell.AppActivate($edge.Id) | Out-Null; Wait # Focus Edge, 'Out-Null' because this prints 'True' on the console
        [System.Windows.Forms.SendKeys]::SendWait("^+a"); Wait # open search box
        [System.Windows.Forms.SendKeys]::SendWait("Dell Command"); Wait
        [System.Windows.Forms.SendKeys]::SendWait("{Tab}{Tab}{Tab}"); Wait
        [System.Windows.Forms.SendKeys]::SendWait("{ENTER}"); Wait; Wait # search for tab
        [System.Windows.Forms.SendKeys]::SendWait("{PGDN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}")
Do { Sleep 5; } Until ( gci "C:\Users\$env:USERNAME\Downloads" | ? { $_.Name -match "Dell-Command" } )
} # END 'If ($Mfgr -and $Mfgr -match "Dell") {'

############### END DCU finder #####################

# Download and run Windows PC Health, and Update Assistant:
# $Ver = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion').DisplayVersion

Sleep 20

$Foldr = "C:\Users\$env:USERNAME\Downloads"
$Apps = "WindowsPCHealthCheckSetup|Windows11InstallationAssistant"
# gci $Foldr | ? { $_.Name -match $Apps } | ri -Force

# Download PC Health Check App and Installation Assistant - Page: https://www.microsoft.com/en-us/software-download/windows11

@("https://aka.ms/GetPCHealthCheckApp","https://go.microsoft.com/fwlink/?linkid=2171764") | % {
start -FilePath "msedge.exe" -ArgumentList $_
}

Get-Process | ? {$_.ProcessName -Match 'OneDrive'} | Stop-Process -Force 

Do { $PC_HC = (gci "$Foldr" | ? { $_.Name -match "WindowsPCHealthCheckSetup.msi" }).FullName } Until ( $PC_HC )
msiexec.exe /i $PC_HC /qn # Install and run it.

Do {Sleep 1} Until ( Test-Path "C:\Users\$env:USERNAME\AppData\Local\PCHealthCheck\PCHealthCheck.exe" )

If (!(gps | ? { $_.Name -match "PCHealthCheck" })) { start "C:\Users\$env:USERNAME\AppData\Local\PCHealthCheck\PCHealthCheck.exe" }

Do { $Asst = (gci "$Foldr" | ? { $_.Name -match "Windows11InstallationAssistant.exe" }).FullName } Until ( $Asst )

Write-Host "
Click the 'Check Now' [BUTTON] in the 'PC Health Check' window...
Then close 'PC Health Check'..." -F 11

$exe = "C:\Users\$env:USERNAME\AppData\Local\PCHealthCheck\PCHealthCheck.exe"
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
    [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"@

$p = Start-Process $exe -PassThru
Start-Sleep -Seconds 2
$p.Refresh()
[Win32]::SetForegroundWindow($p.MainWindowHandle) | Out-Null

Do {$Running = $null; $Running = gps | ? { $_.Name -match "PCHealthCheck" } } Until (!$Running)

$wsh = New-Object -ComObject Wscript.Shell
1..50 | % { $wsh.SendKeys([char]175) }
[System.Media.SystemSounds]::Asterisk.Play()

Write-Host "Starting the 'Installation Assistant'..." -F 14
start "C:\Users\$env:USERNAME\Downloads\Windows11InstallationAssistant.exe"
############### Windows PC Health, and Update Assistant #####################

Return; Break

##~~~~~~~~~  Grab the Office installer ~~~~~~~~~~~~~~

# Start 'https://www.microsoft.com/en-us/download/details.aspx?id=49117'

$dir = "$env:USERPROFILE\Downloads"
New-Item -ItemType Directory -Path "$dir\Office" -Force

$url = "https://github.com/richie65x/MS_OfcDeplyTool/releases/download/v1.0/officedeploymenttool.exe"


curl.exe -k -L $url -o "$dir\officedeploymenttool.exe"

Do { Sleep 5; $ODT = ( gci $dir | ? { $_.Name -match "officedeployment" } ).FullName } Until ( $ODT )

Sleep 3



# Minimize the browser after download completes.
# Use this if using the 'Start 'https://www.microsoft.com...'
<#

gps msedge -ErrorAction SilentlyContinue | Where-Object MainWindowHandle | % {

    $sig = '[DllImport("user32.dll")]public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'

    $type = Add-Type -MemberDefinition $sig -Name NativeMethods -Namespace Win32 -PassThru

    $type::ShowWindowAsync($_.MainWindowHandle, 2) | Out-Null


}

#>

$xmlPath = "$dir\Office\configuration.xml"
$setupExe = "$dir\Office\setup.exe"
# $ODT = (gci $dir | ? { $_.Name -match "officedeployment" }).FullName

$extractArgs = @("/extract:$dir\Office", "/quiet")
$extractProc = Start-Process -FilePath $ODT -ArgumentList $extractArgs -Wait -NoNewWindow -PassThru

$xmlContent = @"

<Configuration>

  <Add OfficeClientEdition="64" Channel="Current">

    <Product ID="O365ProPlusRetail">

      <Language ID="en-us" />

    </Product>

  </Add>

  <Display Level="None" AcceptEULA="TRUE" />

</Configuration>

"@

Set-Content -Path $xmlPath -Value $xmlContent -Encoding Utf8

Write-Host "Downloading and installing Office (Silently - This may take several minutes)..." -F 14

$installArgs = @("/configure", $xmlPath)
$installProc = Start-Process -FilePath $setupExe -ArgumentList $installArgs -Wait -NoNewWindow -PassThru

$Props = @(
'HKLM:\Software\Microsoft\Office\ClickToRun\Configuration',
'SilentlyContinue',
'ProductReleaseIds', 'InstallationPath', 'AudienceData', 'VersionToReport'
)
gp $Props[0]  -ea $Props[1] | fl $Props[2..5]

$wsh = New-Object -ComObject Wscript.Shell
1..50 | % { $wsh.SendKeys([char]175) }
[System.Media.SystemSounds]::Asterisk.Play()

Return; Break

#####################################
Start-Service wuauserv
<#
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Install-PackageProvider -Name NuGet -Force
Install-Module -Name PSWindowsUpdate -Force
Get-Package -Name PSWindowsUpdate -Force
Set-ExecutionPolicy -ExecutionPolicy Bypass -Force
Import-Module PSWindowsUpdate
#>

# 1. TEMPORARILY BYPASS SSL/TLS TRUST VALIDATION FOR THIS SESSION
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

# 2. Enforce TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

# 3. Define paths and download the module manually
$ModulePath = "$env:ProgramFiles\WindowsPowerShell\Modules\PSWindowsUpdate"
if (!(Test-Path $ModulePath)) { New-Item -ItemType Directory -Path $ModulePath -Force }

$TargetZip = "$env:TEMP\pswindowsupdate.zip"
Invoke-WebRequest -Uri "https://powershellgallery.com" -OutFile $TargetZip

# 4. Extract and register
Expand-Archive -Path $TargetZip -DestinationPath $ModulePath -Force
Set-ExecutionPolicy -ExecutionPolicy Bypass -Force
Import-Module PSWindowsUpdate

# 5. Verify it loaded
Get-Command -Module PSWindowsUpdate

# $ErrorActionPreference = "SilentlyContinue"
Get-WUList
Sleep 5
Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -AutoReboot
$ErrorActionPreference = "Continue"
Return
$wsh = New-Object -ComObject Wscript.Shell
1..50 | % { $wsh.SendKeys([char]175) }
[System.Media.SystemSounds]::Asterisk.Play()
###########################

Break
# Enable RDP - and show the active IP address
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 0
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"
(Get-NetIPConfiguration | ? {$_.IPv4DefaultGateway -ne $null -and $_.NetAdapter.status -ne "Disconnected"}).IPv4Address.IPAddress

# Disable the firewall
netsh advfirewall set allprofiles state off
# Set the current connection to 'Private' - By default it is 'Public' so WinRM will not enable.
Set-NetConnectionProfile -InterfaceIndex $((Get-NetConnectionProfile).InterfaceIndex) -NetworkCategory Private
# Enable WinRM
c:\windows\system32\winrm.cmd quickconfig -quiet
# Add DOT.NET 2.0--3.5
# Add-WindowsCapability -Online -Name NetFx3~~~~
###########################

# Get Serial number from BIOS
$SerialNumber = (Get-WmiObject -class win32_bios).SerialNumber
# Dell computers have a shorter Serial number, but others (ie. BeeLink mini's) are too long - This shortens it (to 7 characters) if the SN is longer than 9 characters.
# MPC = Mini PC
If ($SerialNumber.Length -gt 9) { $SerialNumber = "MPC$($SerialNumber.Remove(0, ($SerialNumber.Length - 7)))" }
$SerialNumber
#Read-Host
# Rename the computer to its SN
Rename-Computer -NewName $SerialNumber -Force
Sleep 5
# Gotta reboot
shutdown -r -t 0
###########################

# Make sure you have successfully, and correctly set the computers hostname
hostname

# Enable NumLock
Add-Type -AssemblyName System.Windows.Forms
If ( ! [System.Windows.Forms.Control]:: IsKeyLocked('NumLock') ) {
(New-Object -ComObject WScript.Shell). SendKeys('{NUMLOCK}')
}

[Int]$ChassisType_Q = (Get-CimInstance -ClassName Win32_SystemEnclosure).ChassisTypes | Out-String
$Chassis_All = "Form;ChasVal`nDesktop;3`nLaptop;9`nLaptop;10`nTablet;30`nDesktop;35" | ConvertFrom-Csv -Delimiter ';'
$Chassis_All | % {  $_.ChasVal  = [Int]$_.ChasVal  }
$Chassis = ( $Chassis_All | ? { $_.ChasVal -eq $ChassisType_Q } ).Form
$OUList = "Loc;OU
SVP - Desktop - Prod  ;OU=SVPDskProduction,OU=SVPOU
SVP - Laptop -  Office;OU=SVPLpt10,OU=SVPOU
SVP - Desktop - Office;OU=SVPDskOffice,OU=SVPOU
WCP - Laptop -  Office;OU=WCPLpt10,OU=WCPOU
WCP - Desktop - Prod  ;OU=WCPDskProduction,OU=WCPOU
WCP - Desktop - Office;OU=WCPDskOffice,OU=WCPOU" | ConvertFrom-Csv -Delimiter ';'

If ($Chassis) { $OUList = $OUList | ? { $_.Loc -match $Chassis } }

Do { ''; $Counter = 1
$OUList | % {
If ($_.Loc -match "SVP") { $Bc = 11}; If ($_.Loc -match "WC") { $Bc = 10}
Write-Host "$Counter`:" -F 14 -N; Write-Host " $($_.Loc)" -F $Bc
$Counter++
}
''

Write-Host "Select Location - Enter selection #:" -fore 10 -back 8 -no
Write-Host " [1-$($OUList.Count)]: " -Fore 14 -No
$ErrorActionPreference = "SilentlyContinue"
$ans = $null; [int]$ans = Read-Host } Until ($ans -is [int] -and 1..($OUList.Count) -ccontains $ans)

If (1..$($OUList.Count) -contains $ans) {
$Domain_Name = (Get-DnsClient -InterfaceIndex $((Get-NetConnectionProfile).InterfaceIndex)).ConnectionSpecificSuffix
$OUSffx = ",OU=UsuiOU,OU=UICOU,"; $Domain_Name.Split('.') | % { $OUSffx += "DC=$($_)," }
$OUSffx = $OUSffx.TrimEnd(',')
$OUPath = "$($OUList[$ans-1].OU)$OUSffx"
''; Write-Host "$($OUList[$ans-1].Loc)" -F 14; Write-Host "$OUPath" -F 11;
Add-Computer -domainname $Domain_Name -OUPath $OUPath -ErrorVariable JoinFail
}
$ErrorActionPreference = "Continue"

If ($JoinFail -ge 1) {
Write-Host "Well, that didn't work..." -F 14
Write-Host "'$Domain_Name' is in the clipboard..." -F 0 -B 14
$Domain_Name | Set-Clipboard
cmd.exe /c sysdp.cpl
}
Write-Host "$(hostname)" -F 11
Write-Host "$(hostname)" -F 13
Write-Host "$(hostname)" -F 14
$wsh = New-Object -ComObject Wscript.Shell
1..50 | % { $wsh.SendKeys([char]175) }
[System.Media.SystemSounds]::Asterisk.Play()
Break
# Gotta reboot
shutdown -r -t 0
#---------#
#~##~~~~~~~~~~~~~~~~~~~~~

###########################

# Make sure you have successfully, and correctly set the computers hostname

hostname

# This grabs the full name of the domain

$Domain_Name = (Get-DnsClient -InterfaceIndex $((Get-NetConnectionProfile).InterfaceIndex)).ConnectionSpecificSuffix

# it is possible to add creds to this command - but just enter username, and password at the credential prompt (no need to add 'domain\')

Add-Computer -domainname $Domain_Name

Break

# Gotta reboot

shutdown -r -t 0

###########################


Others...

netsh advfirewall set currentprofile state off

netsh advfirewall set domainprofile state off

netsh advfirewall set privateprofile state off

netsh advfirewall set publicprofile state off