Add Windows firewall rule over PowerShell - windows

I'm adding Windows firewall rules over PowerShell by taking objects from 3 arrays and filling $Params to issue a New-NetFirewallRule command. I can't figure out why my first command is failing with error "Incorrect port number"
Code:
$All = #( '13.79.172.43' , '13.69.228.5' , '1.1.1.1' )
$AllPorts = #( '8883,443' , '443', '80' )
$AllProtocols = #( 'TCP' , 'TCP', 'TCP' )
for ($i = 0; $i -lt $All.Count; $i++) {
$Params = #{
"DisplayName" = '"Block-WiFi-' + $i
"Name" = 'Block-WiFi-' + $i
"Direction" = 'Inbound'
"InterfaceType" = 'Wireless'
"Action" = 'Block'
"RemoteAddress" = $All[$i]
"LocalPort" = $AllPorts[$i]
"Protocol" = $AllProtocols[$i]
}
# Add Windows Firewall RUle
New-NetFirewallRule #Params
# Check what is going on
Write-Host "Address: $($All[$i]) | Port: $($AllPorts[$i]) | Protocol: $($AllProtocols[$i])"
Write-Host "----------------------------------------------------------------------------------"
Start-Sleep 2
}
So everything is working, except when trying to add first 8883,443 object.
When I try command manually it works:
New-NetFirewallRule -DisplayName "Block-Wireless-In-01" -Name "Block-Wireless-In-01" -Direction Inbound -InterfaceType Wireless -Action Block -RemoteAddress 13.79.172.43 -LocalPort 8883,443 -Protocol TCP
Also when I try to add in #Params "LocalPort" = 8883,443 , the rule is added without errors.
Can anybody help me, cos it driving me crazy for two days already.
Thanks in advance!

Parameter -LocalPort of New-NetFirewallRule is declared as an array String[]. So you have to create a nested array when you want to pass multiple ports:
$AllPorts = #( #('8883', '443'), '443', '80' )

Related

Using variables outside a function

I am currently writing my first script in Powershell and I am already facing the first problem.
I would like to read the value from a variable in a function so that I can use this variable in another cmd-let later. The problem now is that the variable is only recognized inside the function block and not outside.
How do I get this to work?
Thanks for the help :-)
function Write-Log([string]$logtext, [int]$level=0)
{
if($level -eq 0)
{
$logtext = "[INFO] " + $logtext
$text = "["+$logdate+"] - " + $logtext
Write-Host $text
}
}
Send-MailMessage -To "<xxx#xxx.de>" -Subject "$text" -Body "The GPO backup creation was completed with the following status: `n $text" -SmtpServer "xxx#xxx.de" -From "xxx#xxx.de"
I would like to submit $text
This has to do with variable scoping behavior in PowerShell.
By default, all variables in the caller's scope is visible inside the function. So we can do:
function Print-X
{
Write-Host $X
}
$X = 123
Print-X # prints 123
$X = 456
Print-X # prints 456
So far, so good. But when we start writing to variables outside the function itself, PowerShell transparently creates a new variable inside the function's own scope:
function Print-X2
{
Write-Host $X # will resolve the value of `$X` from outside the function
$X = 999 # This creates a new `$X`, different from the one outside
Write-Host $X # will resolve the value of the new `$X` that new exists inside the function
}
$X = 123
Print-X2 # Prints 123, and 999
Write-Host $X # But the value of `$X` outside is still 123, unchanged
So, what to do? You could use a scope modifier to write to the variable outside the function, but the real solution here is to return the value from the function instead:
function Write-Log([string]$logtext, [int]$level=0, [switch]$PassThru = $true)
{
if($level -eq 0)
{
$logtext = "[INFO] " + $logtext
$text = "["+$logdate+"] - " + $logtext
Write-Host $text
if($PassThru){
return $text
}
}
}
$logLine = Write-Log "Some log message" -PassThru
Send-MailMessage -Subject $logLine ...
if you need to access a variable outside a function in Powershell you might need to use the global variable.
$global:myglobalvariable="This is a PowerShell global variable"
or if its a null
$global:myglobalvariable2 = $null

Using invoke-webrequest with special chars in URI causes API call to not work correctly

Im doing an script which automates the creation of several things on some firewalls (Sophos XG). This one reads a CSV with 2 column and creates an API call to create IP Host in the firewall with name (first column) and IP (second column). Ideal for massive uploads.
Its works fine, except when some variables have special characters (for example + or &) either in the password variable ($_CONTRASEÑA_API) or the IP's name ($_NOMBRE_IP). If the password or the name doesn't have those chars, it works flawlessly.
Here's the code:
# ---------------------
# Creacion IP Host - XG
# ---------------------
# Versiones
#
# 1.0 - Version original
#
# ---------------------
# Declaracion variables globales
# ------------------------------
$_IP_FIREWALL = "190.80.80.80"
$_PUERTO_FIREWALL = "4444"
$_USUARIO_API = "admin"
$_CONTRASEÑA_API = "SecurePassword+"
$_RUTA_TRABAJO = "c:\Workfolder\IPHostCSV\"
$_NOMBRE_ARCHIVO_CSV = "test.csv"
# Permitir conexiones SSL
# -----------------------
add-type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"#
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
# Bucle principal
# ---------------
foreach($linea in [System.IO.File]::ReadLines("$_RUTA_TRABAJO$_NOMBRE_ARCHIVO_CSV"))
{
# Obtencion Parametros CSV
# ------------------------
$_NOMBRE_IP = ($linea -split ',')[0]
$_DIRECCION_IP = ($linea -split ',')[1]
$_MASCARA = ($linea -split ',')[2]
# Consulta API
# ------------
echo "[INFO] Procesando Host: $($_NOMBRE_IP) IP: $($_DIRECCION_IP)"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$_URL_API = "https://$($_IP_FIREWALL):$($_PUERTO_FIREWALL)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_USUARIO_API)</UserName><Password>$($_CONTRASEÑA_API)</Password></Login><Set><IPHost><Name>$($_NOMBRE_IP)</Name><IPFamily>IPv4</IPFamily><HostType>IP</HostType><IPAddress>$($_DIRECCION_IP)</IPAddress></IPHost></Set></Request>"
$_RESULTADO_API = Invoke-WebRequest -Uri "$_URL_API"
[xml] $_CODIGO_XML = $_RESULTADO_API.Content
# Revision Resultados
# -------------------
if($_CODIGO_XML.Response.IPHost.Status.code -eq 200)
{
echo "[ OK ] CODIGO: $($_CODIGO_XML.Response.IPHost.Status.code) - Procesado OK"
$_NOMBRE_IP | Out-File -Append -Encoding utf8 -FilePath "$($_RUTA_TRABAJO)OK.txt"
} else {
echo "[WARN] CODIGO: $($_CODIGO_XML.Response.IPHost.Status.code) - Problema en la ejecuccion $($_CODIGO_XML.Response.IPHost.Status.'#text')"
$_NOMBRE_IP | Out-File -Append -Encoding utf8 -FilePath "$($_RUTA_TRABAJO)NO_OK.txt"
}
}
Basically, these 2 lines
$_URL_API = "https://$($_IP_FIREWALL):$($_PUERTO_FIREWALL)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_USUARIO_API)</UserName><Password>$($_CONTRASEÑA_API)</Password></Login><Set><IPHost><Name>$($_NOMBRE_IP)</Name><IPFamily>IPv4</IPFamily><HostType>IP</HostType><IPAddress>$($_DIRECCION_IP)</IPAddress></IPHost></Set></Request>"
$_RESULTADO_API = Invoke-WebRequest -Uri "$_URL_API"
[xml] $_CODIGO_XML = $_RESULTADO_API.Content
Do the call. Any idea how to avoid the error when specials chars are used either in password or any other place in the URI?
Thanks!
Antonio.
(Sorry for the English, not my mother tongue).
User the UrlEncode method of HttpUtility. This will convert special character to their url friendly alternative.
$_URL_API_Encoded = [System.Web.HttpUtility]::UrlEncode($_URL_API)
$_RESULTADO_API = Invoke-WebRequest -Uri "$_URL_API_Encoded"

Packetbeat interface detection

I'm using packbeat to monitor network traffic for a SIEM-like setup with ELK. I'd like to push it to a large number of machines but the setup requires manual identification in packetbeat.yml.
Has any been able to script the process of selecting the appropriate interface to monitor for packetbeat?
I've put this together - which uses 3 separate .yml
ConfigTemplate.yml which contains the rest of the packetbeat.yml minus the interfaces.
Interfaces.yml which is a temp file used to write the interfaces to.
packetbeat.yml which is the final config file packetbeat will use.
The python script should be in the packetbeat directory along with the config .yml's
The only limitation is that it needs python on the host machines - the next stage is to see if it can be done with powershell.
Hope this helps anyone else! Any improvements are welcome!
import subprocess
devices = subprocess.check_output(["powershell.exe", "(./packetbeat.exe devices).count"])
devicesCount = int(devices.decode('utf-8'))
print(devicesCount)
deviceCount = range(devicesCount)
with open('ConfigTemplate.yml', 'r') as original: data1 = original.read()
with open('Interfaces.yml', 'w') as modified:
for i in deviceCount:
modified.write("packetbeat.interfaces.device: " + str(i)+ "\n" )
with open('Interfaces.yml', 'r') as original: data2 = original.read()
with open('Packetbeat.yml', 'w') as modified2: modified2.write("# ================== Set listening interfaces ==================" +"\n"+ data2 + "\n" + data1 + "\n")
Powershell version -
$count = (C:\path\to\packetbeat.exe - devices).count
$line = ''
for($i=0; $i -le ($count-1); $i++){
$line +="packetbeat.interfaces.device:"+" $i `r`n"
}
$line | Out-File -FilePath "C:\path\to\packetbeat\Interfaces.yml"
$configTemplate = Get-Content -Path "C:\path\to\packetbeat\ConfigTemplate.yml"
$interfaces = Get-Content -Path "C:\path\to\packetbeat\Interfaces.yml"
$interfaces + "`r`n" + $configTemplate | Out-File -FilePath "C:\path\to\packetbeat\packet.yml"

Powershell thunderbird send email without opening window

I am trying to send email via power shell command to thunder bird but i am facing a problem and did all research dint find the solution
my problem is when i run the below command the power shell adds the provided information but then it opens the window and i have to send it manually but that send also should be done by powershell auto am unable to do that
param(
[string]$attachment='',
[string]$to='test#outlook.com', # used to specify the email of the recipient
[string]$cc='', # used to specify the email of the recipient of a copy of the mail
[string]$bcc='', # used to specify the email of the recipient of a blind copy of the mail*
[string]$subject='test#outlook.com', # subject of the mail
[string]$body='test#outlook.com', # body of the mail
[string]$exec= '"C:\Program Files `(x86`)\Mozilla Thunderbird\thunderbird.exe"' # mail client, if not default type path to Thunderbird installation, eg. C:\Program Files (x86)\Mozilla\Thunderbird\thunderbird.exe
)
# ------ Get default mail client -------
if ($exec) {
$MailClient = $exec + "-compose `"%1`""
}
else {
$node = Get-ItemProperty HKCU:\Software\Classes\mailto\shell\open\command
if (!$node) {
$node = Get-ItemProperty HKLM:\Software\Classes\mailto\shell\open\command
}
$MailClient = $node.'(default)'
}
# TODO check if default client is compatible
# ------ Read email fields -------------
$cmdParams = New-Object Collections.Generic.List[string]
$emailFields = #{"to"=$to; "cc"=$cc; "bcc"=$bcc; "subject"= $subject; "body" = $body}
$emailFields.Keys | % { $value = $emailFields[$_]
if ($value) {
$cmdParams.Add("$_=`'$value`'");
}
}
# Assign ATTACHMENTS
if ($attachment) {
if (Test-Path($attachment)) {
$fullPath = (Get-Item $attachment).FullName;
$cmdParams.Add("attachment=`'$fullPath`'");
} else {
echo "The path `"$file`" does not exists."
}
} elseif (#($input).Count -gt 0) {
# Try to assign ATTACHMENTS parameter from pipeline
$input.reset()
$attachParam = "attachment=`'"
foreach ($filename in $input) {
$fullPath = $filename.FullName + ","
$attachParam += $fullPath
}
$attachParam += "`'"
$cmdParams.Add($attachParam)
}
# ----- Build & run command -------------
$command = ''
if ($cmdParams.Count -gt 0) {
foreach ($param in $cmdParams) {
$command += $param + ","
}
}
$command = $MailClient -replace "`%1", $command
Invoke-Expression "& $command"
If there is no actual requirement to use Thunderbird Send-MailMessage might be an alternative to use.
Using your baseline it could look like the following:
param(
[string]$attachment='C:\Temp\file.txt',
[string]$to='test#outlook.com', # used to specify the email of the recipient
[string]$cc='', # used to specify the email of the recipient of a copy of the mail
[string]$bcc='', # used to specify the email of the recipient of a blind copy of the mail*
[string]$subject='test#outlook.com', # subject of the mail
[string]$body='test#outlook.com', # body of the mail
)
# ------ Get default mail client -------
Send-MailMessage -To $to -Cc $cc -Bcc $bcc -Subject $subject -Body $body -Attachment $attachment -From powershell#example.com -SmtpServer mail.example.com
Most of the fields accept string arrays in case you have multiple CC recipients or simiar.
Notice that you will have to tell Send-MailMessage how to connect to the mail server as it won't magically read your Thunderbird configuration. So you will likely have to include -From, -SmtpServer and maybe even -Credential and -Port depending on how your mail server is configured.
Depending on your requirements you might have to dig a bit deeper and directly use Net.Mail.SmtpClient. There are other questions with examples for it like Send mail via gmail with PowerShell V2's Send-MailMessage.

How to stop power shell script on error?

I have bellow script
$ErrorActionPreference = "Stop";
while($true) {
try {
Write-Host "Step 1";
Dir C:\arts #Error
Write-Host "Step 2";
exit 0
break;
}
catch {
"Error in " + $_.InvocationInfo.ScriptName + " at line: " + $_.InvocationInfo.ScriptLineNumber + ", offset: " + $_.InvocationInfo.OffsetInLine + ".";
$Error
exit 1
break;
}
}
It stops on Dir C:\arts line and that is good for me. As I understood it happens cos I have line $ErrorActionPreference = "Stop"; at the beginning.
I also have some docker params
Param(
[Parameter(Mandatory=$True,ParameterSetName="Compose")]
[switch]$Compose,
[Parameter(Mandatory=$True,ParameterSetName="ComposeForDebug")]
[switch]$ComposeForDebug,
[Parameter(Mandatory=$True,ParameterSetName="StartDebugging")]
[switch]$StartDebugging,
[Parameter(Mandatory=$True,ParameterSetName="Build")]
[switch]$Build,
[Parameter(Mandatory=$True,ParameterSetName="Clean")]
[switch]$Clean,
[parameter(ParameterSetName="Compose")]
[Parameter(ParameterSetName="ComposeForDebug")]
[parameter(ParameterSetName="Build")]
[parameter(ParameterSetName="Clean")]
[ValidateNotNullOrEmpty()]
[String]$Environment = "Debug"
)
If I put $ErrorActionPreference = "Stop" line before docker params I will have error Cannot convert value "System.String" to type "System.Management.Automation.SwitchParameter". Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 or 0.
In case if I put $ErrorActionPreference = "Stop"; line after docker params, script is continued to run and that is not that I want.
I do not know what I need to do here, so I will be grateful for any help
$ErrorActionPreference doesn't work with command line utilities like docker as they don't throw exceptions in PowerShell. You would have to use returncode/errorlevel or parse the output to handle those type of errors. Useful automatic variables:
$?
Contains the execution status of the last operation. It contains
TRUE if the last operation succeeded and FALSE if it failed.
$LastExitCode
Contains the exit code of the last Windows-based program that was run. Same as %errorlevel% in cmd.
If you detect an error, you can throw an exception to stop the script or use something like exit to stop the script. Example:
function Test-Error {
$ErrorActionPreference = "Stop"
Write-Host Before
ping -n 1 123.123.123.123
#If last command was not successfull.
#You can also have checked $lastexitcode, output etc.
if($? -eq $false) {
#Throw terminating error
#throw "Error"
#Or since we've chosen to stop on non-terminating errors, we could use:
Write-Error -ErrorId $LASTEXITCODE -Message "Ping failed"
}
Write-Host After
}
Test-Error
Output:
Before
Pinging 123.123.123.123 with 32 bytes of data:
Request timed out.
Ping statistics for 123.123.123.123:
Packets: Sent = 1, Received = 0, Lost = 1 (100% loss),
Test-Error : Ping failed
At line:22 char:1
+ Test-Error
+ ~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : 1,Test-Error
If you're creating a advanced function, you could set the default ErrorAction for the scope of the cmdlet like this:
function Test-Error {
[CmdLetBinding()]
param(
$Name = "World"
)
#If -ErrorAction is not specified by the user, use Stop for the scope of the function
if(-not $MyInvocation.BoundParameters.ContainsKey("ErrorAction")) { $ErrorActionPreference = "Stop" }
"Hello $Name ! My ErrorAction is: $ErrorActionPreference"
}
PS > $ErrorActionPreference
Continue
PS > Test-Error -ErrorAction Ignore
Hello World ! My ErrorAction is: Ignore
PS > Test-Error
Hello World ! My ErrorAction is: Stop

Resources