So, I've got this script:
function Add-FirewallRule {
param(
$name,
$tcpPorts,
$appName = $null,
$serviceName = $null
)
$fw = New-Object -ComObject hnetcfg.fwpolicy2
$rule = New-Object -ComObject HNetCfg.FWRule
$rule.Name = $name
if ($appName -ne $null) { $rule.ApplicationName = $appName }
if ($serviceName -ne $null) { $rule.serviceName = $serviceName }
$rule.Protocol = 6 #NET_FW_IP_PROTOCOL_TCP
$rule.LocalPorts = $tcpPorts
$rule.Enabled = $true
$rule.Grouping = "#firewallapi.dll,-23255"
$rule.Profiles = 7 # all
$rule.Action = 1 # NET_FW_ACTION_ALLOW
$rule.EdgeTraversal = $false
if(*here*)
{
$fw.Rules.Add($rule)
}
}
and I want to be able to put something in the if() that will check and see if the rule already exists before it adds it. I'm not terribly familiar with powershell, so go easy on me :P
PowerShell Firewall example for SDL Microservices
Only create a new firewall rule if it does not already exist
$rules = Get-NetFirewallRule
$par = #{
DisplayName = ""
LocalPort = 80
Direction="Inbound"
Protocol ="TCP"
Action = "Allow"
}
$par.LocalPort = 8081
$par.DisplayName = "SDL Web 8 Stage Content Microservice on port $($par.LocalPort)"
if (-not $rules.DisplayName.Contains($par.DisplayName)) {New-NetFirewallRule #par}
$par.LocalPort = 8082
$par.DisplayName = "SDL Web 8 Stage Discovery Microservice on port $($par.LocalPort)"
if (-not $rules.DisplayName.Contains($par.DisplayName)) {New-NetFirewallRule #par"}
Why not just:
$r = Get-NetFirewallRule -DisplayName 'Docker Cluster Management Communications' 2> $null;
if ($r) {
write-host "found it";
}
else {
write-host "did not find it"
}
MSDN has some extensive documentation on the Windows Firewall API here:
http://msdn.microsoft.com/en-us/library/aa366449(v=vs.85).aspx
You'll want to start with instantiating the HNetCfg.FwMgr COM object -- this will give you access to query various existing rules via the HNetCfg.FwMgr.LocalPolicy.CurrentProfile.
There are several different types of rules: Authorized Applications, Globally Open Ports, ICMP settings, and "services." The INetFwProfile object (retrieved via the CurrentProfile) has properties that allow access to these rules.
http://msdn.microsoft.com/en-us/library/aa365327(v=vs.85).aspx
Update (2014-01-30): In Windows 8 and Windows Server 2012, there is a PowerShell module called NetSecurity, which contains the Get-NetFirewallRule command. You can use this command to discover which firewall rules are already defined. To add a new firewall rule, use the New-NetFirewallRule command in the same NetSecurity module.
This doesn't seem to be widely known. You can do a fast search of the firewall rules by going first to the filter commands, for example, to list the ones with 'chrome.exe' as the program. You can use a wildcard with -Program, even though it doesn't seem to be documented.
Get-NetFirewallApplicationFilter -Program *chrome.exe | Get-NetFirewallRule |
% Displayname
Google Chrome (mDNS-In)
Get-NetFirewallPortFilter | Where Localport -match 3389 | Get-NetFirewallRule |
% Displayname
Remote Desktop - User Mode (TCP-In)
Remote Desktop - User Mode (UDP-In)
This answer over on serverfault, which was based on this blog-post, might help:
Function Get-EnabledRules
{
Param($profile)
$rules = (New-Object -comObject HNetCfg.FwPolicy2).rules
$rules = $rules | where-object {$_.Enabled -eq $true}
$rules = $rules | where-object {$_.Profiles -bAND $profile}
$rules
}
$networkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"))
$connections = $networkListManager.GetNetworkConnections()
[int[] ] $connTypes = #()
$connTypes = ($connections | % {$_.GetNetwork().GetCategory()})
#$connTypes += 1
Write-Host $connTypes
$connTypes | ForEach-Object {Get-EnabledRules -profile $_ | sort localports,Protocol | format-table -wrap -autosize -property Name, #{Label="Action"; expression={$_.action}}, #{Label="Protocol"; expression={$_.protocol}}, localPorts,applicationname}
you will need to check the enabled rules in your 'if()' ..
You can do it in hacky way, so using Get-NetFirewallRule and surround it in try catch statement. If the rule doesn't exist, it will move us to catch statement so we can create a new rule there.
try {
$firewallRule = Get-NetFirewallRule -DisplayName PROGRAM -ErrorAction Stop
"Firewall rule already exist for program.exe" | Add-Content 'file.log'
}
catch {
if(-Not $firewallRule) {
New-NetFirewallRule -Program $ecfClient -Action Allow -Profile Any -DisplayName "PROGRAM"
"Firewall rule for ecfClient.exe succesffully created" | Add-Content 'file.log'
}
}
You can also check the value from the Get-NetFirewallRule, if the rule exists it will return true because variable isn't empty.
I know it's a dirty way for doing this, but when I was looking for the shortest way that really helped me.
Following up #Trevor Sullivian Suggestion here is test script which achieves the same using NetSecurity Module.
Import-Module NetSecurity
new-netfirewallrule -Action Allow -Direction Inbound -Enabled True -Protocol TCP -LocalPort <<Port>> -DisplayName <<Name>>
Related
We'll be disabling TLSv1.0 and TLSv1.1 on our domain controllers for security reasons. But before we do that, I want to check a list of computers and see which TLS versions they have enabled, to make sure they'll keep authenticating with the domain controllers after the legacy TLS versions are disabled.
I wrote a PowerShell script that loops through the list of computers and runs "Get-TlsCipherSuite", but most of the remote computers don't recognize the command, and I don't want to install it just for this query.
I also run a query on registry "HKLM SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" as per this Microsoft article, but the protocols registry key, does not contain any TLS entries
So basically I'm looking for the correct command or query, which Ideally I will loop through all the computers using PowerShell and get which TLS versions are supported.
Perhaps something like this can help
$cred = Get-Credential -Message "Please enter your admin credentials"
$machines = 'DC01','DC02','DC03' # the list of computernames to check
$result = Invoke-Command -ComputerName $machines -Credential $cred -ScriptBlock {
$supported = [Net.ServicePointManager]::SecurityProtocol
# values from https://learn.microsoft.com/en-us/dotnet/api/system.net.securityprotocoltype
[PsCustomObject]#{
ComputerName = $env:COMPUTERNAME
SystemDefault = [bool]($supported -eq 0)
Ssl3 = [bool]($supported -band 48)
Tls = [bool]($supported -band 192)
Tls11 = [bool]($supported -band 768)
Tls12 = [bool]($supported -band 3072)
Tls13 = [bool]($supported -band 12288)
}
}
# remove the extra properties PowerShell
$result = $result | Select-Object * -ExcludeProperty PS*, RunspaceId
# save to file if you want
$result | Export-Csv -Path 'X:\Somewhere\SecurityProtocols.csv' -NoTypeInformation
# filter out machines supporting Tls1.0 and/or Tls1.1
$result | Where-Object {$_.Tls -eq $true -or $_.Tsl11 -eq $true}
#etc.
I am trying to write a script that will loop through all of my local IIS website and update their physical path credentials whenever I'm forced to update my domain password.
The following works... the first time you run it...
function Set-Site-Credentials(
$SiteElement,
$Credentials
){
$SiteElement.virtualDirectoryDefaults.userName = "$($Credentials.Domain)\$($Credentials.UserName)"
$SiteElement.virtualDirectoryDefaults.password = $Credentials.Password
$SiteElement | Set-Item -Force
}
After running this, I noticed that the following properties also get set
$SiteElement.userName #Same as was set earlier on .virtualDirectoryDefaults
$SiteElement.password #Same as was set earlier on .virtualDirectoryDefaults
Subsequently, anytime I try to update the credentials using the code above, these two properties remain unchanged, and the changes don't take affect in IIS.
So the result is:
$SiteElement.userName #Unchanged
$SiteElement.password #Unchanged
$SiteElement.virtualDirectoryDefaults.userName #New value
$SiteElement.virtualDirectoryDefaults.password #New value
And the IIS site still shows the old username in the UI and the credentials fail.
So naturally I tried setting those extra 2 properties in my update function:
function Set-Site-Credentials(
$SiteElement,
$Credentials
){
$SiteElement.userName = "$($Credentials.Domain)\$($Credentials.UserName)"
$SiteElement.password = $Credentials.Password
$SiteElement.virtualDirectoryDefaults.userName = "$($Credentials.Domain)\$($Credentials.UserName)"
$SiteElement.virtualDirectoryDefaults.password = $Credentials.Password
$SiteElement | Set-Item -Force
}
The code throws no errors or warnings, but the end result is the same, those 2 extra properties remain unchanged.
I am using the following code to get "$SiteElement"
$sites = Get-ChildItem IIS:\Sites
$sites | Foreach-Object { Set-Site-Credentials -SiteElement $_ -Credentials $newCredentials }
Also, at the end of the script I restart IIS using this command:
Restart-Service W3SVC
Ugh, finally found a command that works. All in all I've tried 4 different variation of the same thing from different example around the interwebz, all of which only work the first time. But this command updates properly on subsequent changes:
function Set-Site-Credentials(
$SiteElement,
$Credentials
){
Set-WebConfiguration -Filter "$($SiteElement.ItemXPath)/application[#path='/']/virtualDirectory[#path='/']" -Value #{userName="$($Credentials.Domain)\$($Credentials.UserName)"; password="$($Credentials.Password)"}
}
The full script
param (
[switch]$All,
[switch]$AllPools,
[switch]$AllSites,
[string]$AppPool,
[string]$Site
)
Import-Module WebAdministration
function Set-AppPool-Credentials(
$AppPoolElement,
$Credentials
){
Set-ItemProperty $AppPoolElement.PSPath -name processModel -value #{userName="$($Credentials.Domain)\$($Credentials.UserName)";password="$($Credentials.Password)";identitytype=3}
}
function Set-Site-Credentials(
$SiteElement,
$Credentials
){
Set-WebConfiguration -Filter "$($SiteElement.ItemXPath)/application[#path='/']/virtualDirectory[#path='/']" -Value #{userName="$($Credentials.Domain)\$($Credentials.UserName)"; password="$($Credentials.Password)"}
}
$newCredentials = (Get-Credential).GetNetworkCredential()
$appPools = Get-ChildItem IIS:\AppPools
$sites = Get-ChildItem IIS:\Sites
if($All -or $AllPools){
$appPools | Foreach-Object { Set-AppPool-Credentials -AppPoolElement $_ -Credentials $newCredentials }
}
elseif($AppPool){
$poolElement = ($appPools | Where-Object { $_.name -eq $AppPool })
Set-AppPool-Credentials -AppPoolElement $poolElement -Credentials $newCredentials
}
if($All -or $AllSites){
$sites | Foreach-Object { Set-Site-Credentials -SiteElement $_ -Credentials $newCredentials }
}
elseif($Site){
$siteElement = ($sites | Where-Object { $_.name -eq $Site })
Set-Site-Credentials -SiteElement $siteElement -Credentials $newCredentials
}
Restart-Service W3SVC
I'm currently trying to put together a script that queries AD for a list of computers, pings the computers to determine which ones are still active, and then telnets into a specific port on all the pingable computers. The output I'm looking for is a full list of pingable computers in AD for which I can't telnet to the said port.
I've read these few questions, but they don't quite hit on what I'm trying to do. I just want to see if the telnet connection is successful without entering telnet (or automate the quitting of telnet) and move on to the next machine to test. The AD and pinging portions of my script are set, I'm just stuck here. The things I've tried haven't quite worked as planned.
Here is the code for the first parts of the script, if needed:
Get-ADComputer -Filter * -SearchBase 'DC=hahaha,DC=hehehe' | ForEach {
$computerName = $_.Name
$props = #{
ComputerName = $computerName
Alive = $false
PortOpen = $false
}
If (Test-Connection -ComputerName $computerName -Count 1 -Quiet) {
$props.Alive = $true
}
Adapting this code into your own would be the easiest way. This code sample comes from the PowerShellAdmin wiki. Collect the computer and port you want to check. Then attempt to make a connection to that computer on each port using Net.Sockets.TcpClient.
foreach ($Computer in $ComputerName) {
foreach ($Port in $Ports) {
# Create a Net.Sockets.TcpClient object to use for
# checking for open TCP ports.
$Socket = New-Object Net.Sockets.TcpClient
# Suppress error messages
$ErrorActionPreference = 'SilentlyContinue'
# Try to connect
$Socket.Connect($Computer, $Port)
# Make error messages visible again
$ErrorActionPreference = 'Continue'
# Determine if we are connected.
if ($Socket.Connected) {
"${Computer}: Port $Port is open"
$Socket.Close()
}
else {
"${Computer}: Port $Port is closed or filtered"
}
# Apparently resetting the variable between iterations is necessary.
$Socket = $null
}
}
Here is a complete powershell script that will:
1. read the host and port details from CSV file
2. perform telnet test
3. write the output with the test status to another CSV file
checklist.csv
remoteHost,port
localhost,80
asdfadsf,83
localhost,135
telnet_test.ps1
$checklist = import-csv checklist.csv
$OutArray = #()
Import-Csv checklist.csv |`
ForEach-Object {
try {
$rh = $_.remoteHost
$p = $_.port
$socket = new-object System.Net.Sockets.TcpClient($rh, $p)
} catch [Exception] {
$myobj = "" | Select "remoteHost", "port", "status"
$myobj.remoteHost = $rh
$myobj.port = $p
$myobj.status = "failed"
Write-Host $myobj
$outarray += $myobj
$myobj = $null
return
}
$myobj = "" | Select "remoteHost", "port", "status"
$myobj.remoteHost = $rh
$myobj.port = $p
$myobj.status = "success"
Write-Host $myobj
$outarray += $myobj
$myobj = $null
return
}
$outarray | export-csv -path "result.csv" -NoTypeInformation
result.csv
"remoteHost","port","status"
"localhost","80","failed"
"asdfadsf","83","failed"
"localhost","135","success"
I would like to write a script to check radom IP or hostname to see if ports are open. Here is what I have so far. The scripts name is checkports.
foreach ($xhost in $computername){
Write-Host $xhost
foreach ($port in $ports) {
$Socket = New-Object System.Net.Sockets.TCPClient
$Connection = $Socket.BeginConnect($xhost,$port,$null,$null)
$Connection.AsyncWaitHandle.WaitOne(5000,$false) | out-null
if ($Connection -eq $true)
{ write-host = "$xhost port $port is open" }
else
{ write-host = "port $port is closed" }
$Socket.EndConnect($Connection)
$Socket.Close()
}
}
I would like to input values in the following way:
.\checkport '192.186.1.5'
or
'192.168.1.5', '192.168.1.105', 192.168.1.110' | checkport
It doesn't seem to be reading IP address or displaying results.
I was wondering if anyone could point out there could show me what I am doing wrong in with this script?
I've been able to use the 'Test-Port' function from Boe Prox for similar scan/ reporting functions, the code is available on PoshCode:
http://poshcode.org/2514
When I needed to test ports for Directory health, I built a csv with 'port' and 'protocol' columns, then added the port number/ protocol for each port to check. This was used in the following script:
. .\test-port.ps1
$computersToCheck = get-content .\computers.txt
$portList = Import-CSV .\portList.csv
foreach($entry in $portList)
{
$testPortParams = #{
port = $($entry.port)
}
if( $($entry.protocol) -eq "tcp")
{ $testPortParams += #{ TCP = $true } }
else
{ $testPortParams += #{ UDP = $true } }
$outLog = "portTest-$($entry.port)-$($entry.protocol).txt"
$computersToCheck |
Test-Port #testPortParams |
Sort-Object -Property open,name -descending |
format-table -auto -outVariable status
Add-Content -path $outLog -value $status
}
You could certainly build a feeder script to build the range of IP addresses and ports to scan.
In BizTalk Server Administration Console you can query for suspended service instances and then filter them by Application Name. I need such functionality without BTS Administration Console.
So far I've created Powershell script to get suspended instances:
$array = Get-WmiObject MSBTS_ServiceInstance `
-Namespace 'root\MicrosoftBizTalkServer' `
-Filter '(ServiceClass = 4 or ServiceClass = 1) `
and (ServiceStatus = 4 or ServiceStatus = 16)'
foreach ($element in $array)
{
Write-Host $element.InstanceID "-" $element.HostName "-" `
$element.ServiceStatus "-" $element.ServiceClass
}
If you run this script you'll get all suspended instances, but how to find out to what application they belong?
Any solution that uses PowerShell, WMI or C# is good for me.
I've used the Microsoft.BizTalk.Operations assembly ...
Add-Type -AssemblyName ('Microsoft.BizTalk.Operations, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL')
$dbServer = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0\Administration' 'MgmtDBServer').MgmtDBServer
$dbName = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0\Administration' 'MgmtDBName').MgmtDBName
$bo = New-Object Microsoft.BizTalk.Operations.BizTalkOperations $dbServer, $dbName
$serviceInstances = $bo.GetServiceInstances()
$tgt = "DeploymentFramework.Samples.HelloWorld"
foreach ($instance in $serviceInstances)
{
if ($instance.Application -ieq $tgt)
{
$completionStatus= $bo.TerminateInstance($instance.Id)
}
}
One thing I've not worked out ... Why does terminating a suspended (not resumable) service instance return Failed, yet it is terminated
Application name property is not exposed via MSBTS_ServiceInstance class. I believe the reason for that is, application concept was only introduced in BizTalk 2006 but the WMI API was present right from 2004.
I'm afraid, your only choice is to go directly to the database.
What version of BizTalk?
This works on BizTalk 2010:
$array = Get-WmiObject MSBTS_ServiceInstance `
-Namespace 'root\MicrosoftBizTalkServer' `
-Filter '(ServiceClass = 4 or ServiceClass = 1) `
and (ServiceStatus = 4 or ServiceStatus = 16)'
foreach ($element in $array)
{
Write-Host $element.ServiceName
}