How To Use NXLog On A Windows Client

Step 1: Setup Server
- Install a log aggregation server is out of scope of this document

Step 2: Setup Client
- Download and install NXLog Client:
  - Latest edition: https://nxlog.co/products/nxlog-community-edition/download
  - Automated install: choco install -y nxlog (version 2.10.2150 as of August 2021)
- Readme File content:
    Please edit the configuration file after installation. This file is
    located in the `conf` directory where NXLog was installed (default
    `C:\Program Files (x86)\nxlog\conf\nxlog.conf` on 64-bit Windows). If
    you chose a custom installation directory, you will need to update the
    ROOT directory specified in the configuration file before the NXLog
    service will start.

    The NXLog service can be started from the Services console (run
    `services.msc`) or will be started automatically at the next
    boot. Alternatively, the service can be started by executing
    `nxlog.exe`, located in the installation directory. The `-f` command
    line argument can be used to run NXLog in the foreground.

    By default, NXLog will write its own messages to the log file named
    `nxlog.log` in the `data` directory (default `C:\Program Files
    (x86)\nxlog\data\nxlog.log` on 64-bit Windows). If you have trouble
    starting or running NXLog, check that file for errors.

    See the NXLog Reference Manual for details about configuration and
    usage. The Reference Manual is installed in the `doc` directory
    (default `C:\Program Files (x86)\nxlog\doc` on 64-bit Windows) and
    should also be available online at <https://nxlog.co/resources>.
- Configure:
  - How to configure: https://nxlog.co/eventlog-to-syslog
  - Edit the file at C:\Program Files (x86)\nxlog\conf\nxlog.conf  

# Uncomment these line if using Graylog
#<Extension _gelf>
#    Module xm_gelf
#</Extension>

# How to generate query: https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/advanced-xml-filtering-in-the-windows-event-viewer/ba-p/399761
# Please note that indentation is important!
<Input im_msvistalog>
    Module      im_msvistalog
    Query   <QueryList>\
        	<Query Id="0">\
                # This is an example of Windows logon RDP mode 10
            		<Select Path="Security">*[System[(EventID=4624)]] and *[EventData[(Data=10)]]</Select>\
        	</Query>\
    	</QueryList>
</Input>

<Output om_udp>
  Module  om_udp
  Host  [IPADDRESSHERE]
  Port  514
  Exec  to_syslog_snare(); # Use this if Graylog: OutputType  GELF
</Output>

<Route out>
  Path  im_msvistalog  => om_udp
</Route>

- Confirm whether remote host port is reachable from client
  PS C:\Windows\system32> test-netconnection syslog-server -port 514
  ComputerName           : syslog-server
  RemoteAddress          : x.x.x.x
  RemotePort             : 514
  InterfaceAlias         : Ethernet 2
  SourceAddress          : x.x.x.x
  PingSucceeded          : True
  PingReplyDetails (RTT) : 1 ms
  TcpTestSucceeded       : True

- Start NXLog client service
  PS C:\Windows\system32> start-service NXLog

- Troubleshooting
  - Sample problem:
    PS C:\Windows\system32> start-service nxlog
    start-service : Service 'nxlog (nxlog)' cannot be started due to the following error: Cannot start service nxlog on
    computer '.'.
    At line:1 char:1
    + start-service nxlog
    + ~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Service],
      ServiceCommandException
        + FullyQualifiedErrorId : CouldNotStartService,Microsoft.PowerShell.Commands.StartServiceCommand

    PS C:\Windows\system32> &"C:\Program Files (x86)\nxlog\nxlog.exe" -c "C:\Program Files (x86)\nxlog\conf\nxlog.conf"
    Expected </Input> but saw </Query> at C:\Program Files (x86)\nxlog\conf\nxlog.conf:53
  - Resolution to error message above is to fix the indentation of the config file

- Check service connections
  PS C:\Windows\system32> netstat -nbt| select-string -Pattern "nxlog" -Context 2
    [rstudio.exe]
      TCP    127.0.0.1:61682        127.0.0.1:61683        ESTABLISHED
  >  [nxlog.exe]
      TCP    127.0.0.1:61683        127.0.0.1:61682        ESTABLISHED

- Check server for established tcp connections
  [thanos@syslog-server thanos] #
  remoteIP=x.x.x.x
  match=$null
  while [ -z "$match" ]
  do
    clear
    echo "Checking for incoming connection from $remoteIP"
    match=$(netstat -na|grep $remoteIP)
    [[ ! -z "$match" ]] && echo "$match" || sleep 1
  done

- check which daemons & owners listen to which ports
  [thanos@syslog-server thanos] # netstat -elpt
  Active Internet connections (only servers)
  Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode      PID/Program name
  tcp        0      0 0.0.0.0:sunrpc          0.0.0.0:*               LISTEN      root       7956       1/systemd
  tcp        0      0 0.0.0.0:33427           0.0.0.0:*               LISTEN      root       13042      -
  tcp        0      0 localhost:domain        0.0.0.0:*               LISTEN      systemd-resolve 8111       673/systemd-resolve
  tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN      root       12384      1162/sshd: /usr/sbi
  tcp        0      0 localhost.localdom:smtp 0.0.0.0:*               LISTEN      root       9157       787/master
  tcp        0      0 0.0.0.0:46463           0.0.0.0:*               LISTEN      rpcuser    12960      1275/rpc.statd
  tcp        0      0 0.0.0.0:shell           0.0.0.0:*               LISTEN      root       11650      1252/rsyslogd
  tcp        0      0 localhost.localdom:smux 0.0.0.0:*               LISTEN      root       9674       811/snmpd

- Check RDP logging activities
  client=SYSLOGCLIENT
  year=$(date +"%Y")
  clientlog=/var/log/rsyslog/hosts/$client/$year/messages
  rdpLogFilter=".*Source Port:  \w+"
  tail -f $clientlog | grep -oP $rdpLogFilter
  cat $clientlog | grep -oP $rdpLogFilter

Configuration Example 1:

Panic Soft
#NoFreeOnExit TRUE

define ROOT     C:\Program Files (x86)\nxlog
define CERTDIR  %ROOT%\cert
define CONFDIR  %ROOT%\conf
define LOGDIR   %ROOT%\data
define LOGFILE  %LOGDIR%\nxlog.log
LogFile %LOGFILE%

Moduledir %ROOT%\modules
CacheDir  %ROOT%\data
Pidfile   %ROOT%\data\nxlog.pid
SpoolDir  %ROOT%\data

<Extension _syslog>
    Module      xm_syslog
</Extension>

<Extension _charconv>
    Module      xm_charconv
    AutodetectCharsets iso8859-2, utf-8, utf-16, utf-32
</Extension>

<Extension _exec>
    Module      xm_exec
</Extension>

<Extension _fileop>
    Module      xm_fileop

    # Check the size of our log file hourly, rotate if larger than 5MB
    <Schedule>
        Every   1 hour
        Exec    if (file_exists('%LOGFILE%') and \
                   (file_size('%LOGFILE%') >= 5M)) \
                    file_cycle('%LOGFILE%', 8);
    </Schedule>

    # Rotate our log file every week on Sunday at midnight
    <Schedule>
        When    @weekly
        Exec    if file_exists('%LOGFILE%') file_cycle('%LOGFILE%', 8);
    </Schedule>
</Extension>

<Extension _gelf>
    Module xm_gelf
</Extension>

# How to generate query: https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/advanced-xml-filtering-in-the-windows-event-viewer/ba-p/399761
# Please note that indentation is important!
<Input from_eventlog>
    Module      im_msvistalog
    <QueryXML>
        <QueryList>
            <Query Id="0">
                <Select Path="Security">
                    *[System[Level=0 and (EventID=4624 or EventID=4647)]]
                </Select>
            </Query>
        </QueryList>
    </QueryXML>
</Input>

# Source: https://nxlog.co/documentation/nxlog-user-guide/forwarding.html
<Output om_udp>
    Module      om_udp # OR om_tcp (depending on server listening port discovered in http://{graylog.server.url}/system/inputs)
    Host        10.10.10.88
    Port        12222
    OutputType  GELF_UDP # OR GELF_TCP OR Exec to_syslog_ietf(); OR to_syslog_snare(); OR Binary OR to_json(); 
</Output>

<Route out>
    Path    from_eventlog  => out
</Route>

Configuration Example 2:

Panic Soft
#NoFreeOnExit TRUE
 
define ROOT     C:\Program Files (x86)\nxlog
define CERTDIR  %ROOT%\cert
define CONFDIR  %ROOT%\conf
define LOGDIR   %ROOT%\data
define LOGFILE  %LOGDIR%\nxlog.log
LogFile %LOGFILE%
 
Moduledir %ROOT%\modules
CacheDir  %ROOT%\data
Pidfile   %ROOT%\data\nxlog.pid
SpoolDir  %ROOT%\data
 
<Extension _syslog>
    Module      xm_syslog
</Extension>
 
<Extension _charconv>
    Module      xm_charconv
    AutodetectCharsets iso8859-2, utf-8, utf-16, utf-32
</Extension>
 
<Extension _exec>
    Module      xm_exec
</Extension>
 
<Extension _fileop>
    Module      xm_fileop
 
    # Check the size of our log file hourly, rotate if larger than 5MB
    <Schedule> 
        Every   1 hour
        Exec    if (file_exists('%LOGFILE%') and \
                   (file_size('%LOGFILE%') >= 5M)) \
                    file_cycle('%LOGFILE%', 8);
    </Schedule>
 
    # Rotate our log file every week on Sunday at midnight
    <Schedule>
        When    @weekly
        Exec    if file_exists('%LOGFILE%') file_cycle('%LOGFILE%', 8);
    </Schedule>
</Extension>
 
<Extension _gelf>
    Module xm_gelf
</Extension>
 
<Input im_msvistalog>
    Module      im_msvistalog
    Query   <QueryList>\
        	<Query Id="0">\
					<Select Path="System">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\
            		<Select Path="Application">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\
					<Select Path="Security">*[System[Level=0 and (EventID=4624 or EventID=4647)]]</Select>\
        	</Query>\
    	</QueryList>
</Input>

<Output send_graylog>
    Module      om_tcp
    Host        10.10.10.88
    Port        12201
    OutputType  GELF_TCP
</Output>

<Processor norepeat>
	Module pm_norepeat
	CheckFields Message
</Processor>

<Route out>
    Path    im_msvistalog  => norepeat => send_graylog
</Route>

Example 3:

Panic Soft
#NoFreeOnExit TRUE
 
define ROOT     C:\Program Files (x86)\nxlog
define CERTDIR  %ROOT%\cert
define CONFDIR  %ROOT%\conf
define LOGDIR   %ROOT%\data
define LOGFILE  %LOGDIR%\nxlog.log
LogFile %LOGFILE%
 
Moduledir %ROOT%\modules
CacheDir  %ROOT%\data
Pidfile   %ROOT%\data\nxlog.pid
SpoolDir  %ROOT%\data
 
<Extension _syslog>
    Module      xm_syslog
</Extension>
 
<Extension _charconv>
    Module      xm_charconv
    AutodetectCharsets iso8859-2, utf-8, utf-16, utf-32
</Extension>
 
<Extension _exec>
    Module      xm_exec
</Extension>
 
<Extension _fileop>
    Module      xm_fileop
 
    # Check the size of our log file hourly, rotate if larger than 5MB
    <Schedule> 
        Every   1 hour
        Exec    if (file_exists('%LOGFILE%') and \
                   (file_size('%LOGFILE%') >= 5M)) \
                    file_cycle('%LOGFILE%', 8);
    </Schedule>
 
    # Rotate our log file every week on Sunday at midnight
    <Schedule>
        When    @weekly
        Exec    if file_exists('%LOGFILE%') file_cycle('%LOGFILE%', 8);
    </Schedule>
</Extension>
 
<Extension _gelf>
    Module xm_gelf
</Extension>

# This example would filter the Windows Event Logs to capture only Network and Interactive logons
# Sources:
# - https://nxlog.co/documentation/nxlog-user-guide/eventlog-filtering.html
# - https://eventlogxp.com/blog/logon-type-what-does-it-mean/
<Input winEvents>
    Module      im_msvistalog
    Query   <QueryList>\
        	<Query Id="0">\
					<Select Path="Security">*[System[Level=0 and (EventID=4624 or EventID=4647)]]</Select>\
        	</Query>\
    	</QueryList>
	<Exec>
        if ($TargetUserName == "SYSTEM" OR $LogonType in ("4", "5", "7", "9"))
		drop();
    </Exec>
</Input>

<Output send_graylog>
    Module      om_tcp
    Host        0.0.100.88
    Port        12201
    OutputType  GELF_TCP
</Output>

<Processor norepeat>
	Module pm_norepeat
	CheckFields Message
</Processor>

<Route out>
    Path    winEvents => norepeat => send_graylog
</Route>

Active Directory Group Policy – HIPPA Auditing

The Health Insurance Portability and Accountability Act of 1996 (HIPAA) is a federal law that required the creation of national standards to protect sensitive patient health information from being disclosed without the patient’s consent or knowledge.

Organizations within the scope of this realm are to setup certain security postures that would enhance information security. Below is a sample set of recommended rules that should be applied toward Windows Active Directory.

Scope:
  - Applies to Domain Controllers and HIPPA Zones
  - Security filtering: NT AUTHORITY\Authenticated Users
Policies:
  - Windows Settings > Security Settings > Local Policies/Audit Policy:
    - Audit account logon events
    - Audit account management
    - Audit directory service access
    - Audit logon events
    - Audit object access
    - Audit policy Change
    - Audit privilege use 
    - Audit process tracking
    - Audit system events
  - Windows Settings > Security Settings > Local Policies/User Rights Assignment
    - Allow log on through Terminal Services:
      - Domain Admins
      - BUILTIN\Administrators
      - Remote Desktop Users (removed)
Log Retention:
  - Retention period: 1-year

Setting Windows Security Auditing via Command Line

# Check all policies
auditpol /get /Category:*
# Sample output
PS C:\WINDOWS\system32> auditpol /get /Category:*
System audit policy
Category/Subcategory                      Setting
System
  Security System Extension               No Auditing
  System Integrity                        Success and Failure
  IPsec Driver                            No Auditing
  Other System Events                     Success and Failure
  Security State Change                   Success
Logon/Logoff
  Logon                                   Success and Failure
  Logoff                                  Success
  Account Lockout                         Success
  IPsec Main Mode                         No Auditing
  IPsec Quick Mode                        No Auditing
  IPsec Extended Mode                     No Auditing
  Special Logon                           Success
  Other Logon/Logoff Events               No Auditing
  Network Policy Server                   Success and Failure
  User / Device Claims                    No Auditing
  Group Membership                        No Auditing
Object Access
  File System                             No Auditing
  Registry                                No Auditing
  Kernel Object                           No Auditing
  SAM                                     No Auditing
  Certification Services                  No Auditing
  Application Generated                   No Auditing
  Handle Manipulation                     No Auditing
  File Share                              No Auditing
  Filtering Platform Packet Drop          No Auditing
  Filtering Platform Connection           No Auditing
  Other Object Access Events              No Auditing
  Detailed File Share                     No Auditing
  Removable Storage                       No Auditing
  Central Policy Staging                  No Auditing
Privilege Use
  Non Sensitive Privilege Use             No Auditing
  Other Privilege Use Events              No Auditing
  Sensitive Privilege Use                 No Auditing
Detailed Tracking
  Process Creation                        No Auditing
  Process Termination                     No Auditing
  DPAPI Activity                          No Auditing
  RPC Events                              No Auditing
  Plug and Play Events                    No Auditing
  Token Right Adjusted Events             No Auditing
Policy Change
  Audit Policy Change                     Success
  Authentication Policy Change            Success
  Authorization Policy Change             No Auditing
  MPSSVC Rule-Level Policy Change         No Auditing
  Filtering Platform Policy Change        No Auditing
  Other Policy Change Events              No Auditing
Account Management
  Computer Account Management             No Auditing
  Security Group Management               Success
  Distribution Group Management           No Auditing
  Application Group Management            No Auditing
  Other Account Management Events         No Auditing
  User Account Management                 Success
DS Access
  Directory Service Access                No Auditing
  Directory Service Changes               No Auditing
  Directory Service Replication           No Auditing
  Detailed Directory Service Replication  No Auditing
Account Logon
  Kerberos Service Ticket Operations      No Auditing
  Other Account Logon Events              No Auditing
  Kerberos Authentication Service         No Auditing
  Credential Validation                   No Auditing
# Enable Audit Access - Success
auditpol /set /category:"Object Access" /success:enable
# Sample result:
PS C:\WINDOWS\system32> auditpol /get /category:"Object Access"
System audit policy
Category/Subcategory                      Setting
Object Access
  File System                             Success
  Registry                                Success
  Kernel Object                           Success
  SAM                                     Success
  Certification Services                  Success
  Application Generated                   Success
  Handle Manipulation                     Success
  File Share                              Success
  Filtering Platform Packet Drop          Success
  Filtering Platform Connection           Success
  Other Object Access Events              Success
  Detailed File Share                     Success
  Removable Storage                       Success
  Central Policy Staging                  Success
# Disable Audit Access - Success
auditpol /set /category:"Object Access" /success:disable
# Sample result:
PS C:\WINDOWS\system32> auditpol /get /category:"Object Access"
System audit policy
Category/Subcategory                      Setting
Object Access
  File System                             No Auditing
  Registry                                No Auditing
  Kernel Object                           No Auditing
  SAM                                     No Auditing
  Certification Services                  No Auditing
  Application Generated                   No Auditing
  Handle Manipulation                     No Auditing
  File Share                              No Auditing
  Filtering Platform Packet Drop          No Auditing
  Filtering Platform Connection           No Auditing
  Other Object Access Events              No Auditing
  Detailed File Share                     No Auditing
  Removable Storage                       No Auditing
  Central Policy Staging                  No Auditing
# Enable other access audits - use sparingly
auditpol /set /category:"System","Account Management","Account Logon","Logon/Logoff","Policy Change" /failure:enable /success:enable

auditpol /set /category:"DS Access","Object Access" /failure:enable

How To Turn On Windows SMB File Share Access Auditing

Step 1: Turn on File Editing

CLI method:

# Enable Audit Access - Success
auditpol /set /category:"Object Access" /success:enable

GUI method:

Run: GPEDIT.MSC > Computer Configuration > Security Settings > Local Policies > Audit Policy > double-click ‘Audit object access’ > put check marks next to ‘Success’ and ‘Failures’ > OK

Step 2: Apply Audit Policy to Shared Folders

Run: explorer.exe > navigate to Shared folder > right-click folder and select Properties > click on Security tab > Advanced

Click on Auditing tab > if the Auditing entries are empty, click Add

Set Principle as ‘everyone’ > Applies to ‘This folder, subfolders and files’ > insert check marks next to ‘Read & execute’, ‘List folder contents’, and ‘Read’ > OK

Click OK or Continue to bypass these warnings

Step 3: Test

Logon to SMB Server to check event log (eventvwr.exe) > navigate to Windows Logs > right-click Security > Filter current log >  input value ‘5140’, as shown in the list below, into the Event IDs field > OK

SMB Access Event IDs List:

5140(S, F): A network share object was accessed.
5142(S): A network share object was added.
5143(S): A network share object was modified.
5144(S): A network share object was deleted.
5145(S): A network share object was checked to see whether client can be granted desired access (Synchronize, ReadData, ListDirectory, ReadAttribute)
5168(F): SPN check for SMB/SMB2 failed.

Access the SMB share path from a remote machine to open a file on the SMB Server > Return to SMB Server console session to refresh the event viewer and see the ‘Audit Success’ item

Here’s a sample text of the event above:

A network share object was accessed.

Subject:
Security ID: intranet\TestUser
Account Name: TestUser
Account Domain: intranet
Logon ID: 0x80160F50

Network Information:
Object Type: File
Source Address: 10.10.10.10
Source Port: 58341

Share Information:
Share Name: \\*\IPC$
Share Path:

Access Request Information:
Access Mask: 0x1
Accesses: ReadData (or ListDirectory)

 

How to Disable or Remove Windows Defender

Step 1: Disable Real-time monitoring immediately to minimize current runtime memory resource utilization
Set-MpPreference -DisableRealtimeMonitoring $true
Step 2: Remove Windows Defender
# This works well on Server OS 
Remove-WindowsFeature Windows-Defender, Windows-Defender-GUI
# Uninstall-WindowsFeature -Name Windows-Defender # Alternate command
# This only works on Client OS, not Server OS
$winDefendHive='REGISTRY::HKLM\SOFTWARE\Policies\Microsoft\Windows Defender'
$keyName='DisableAntiSpyware'
$disableValue=1
New-ItemProperty -Path $winDefendHive -Name $keyName -Value $disableValue -PropertyType DWORD -Force
# This error would occurs because Windows Defender on servers do not have this registry hive
New-ItemProperty : Cannot find path 'HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender' because it does not exist.
At line:1 char:1
+ New-ItemProperty -Path 'REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Policie ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (HKEY_LOCAL_MACH...indows Defender:String) [New-ItemProperty], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.NewItemPropertyCommand
Alternative Method: Disable WinDefend via local GPO

Run gpedit.msc > Computer Configuration > Administrative Templates > Windows Components > Microsoft Defender Antivirus >
set Turn off Windows Defender Antivirus = Enabled, Turn off real time protection = Disabled > close gpedit > run ‘gpupdate /force’

Other Commands:
# How to add permissions to WinDefend Registry hive
$winDefenderKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Services\WinDefend",[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::ChangePermissions)
$acl = $winDefenderKey.GetAccessControl()
$rule = New-Object System.Security.AccessControl.RegistryAccessRule("Builtin\Administrators","FullControl","ContainerInherit","None","Allow")
$acl.AddAccessRule($rule)
$winDefenderKey.SetAccessControl($acl)

# How to set the startup type of the Windows Defender's service to "Automatic"
Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\WinDefend -Name Start -Value 0x00000002

# How to set Windows Defender's service to disable on startup
Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\WinDefend -Name Start -Value 0x00000003

# Check WinDefend settings
Get-MpComputerStatus | Select-Object -Property Antivirusenabled,AMServiceEnabled,AntispywareEnabled,BehaviorMonitorEnabled,IoavProtectionEnabled,NISEnabled,OnAccessProtectionEnabled,RealTimeProtectionEnabled,AntivirusSignatureLastUpdated

# Kill WinDefend using the old-school DISM tool
Dism /online /Disable-Feature /FeatureName:Windows-Defender /Remove /NoRestart /quiet

# Example on uninstallation of AV and WinDefend - to be followed up with Installating a new AV
$computernames=@(
    'SERVER0001',
    'SERVER0002',
    'SERVER0003'
    )
$installFile='C:\Temp\xdr6.1.1.msi'
$uninstallPassword='UNINSTALLPASSWORD'
foreach ($computername in $computernames){
    copy-item $installFile -destination "\\$computername\c$\Temp"
    $localInstallFile="C:\Temp\$(split-path $installFile -leaf)"
    invoke-command -computername $computername -scriptblock{
        param($installFile,$uninstallPassword,$logFolder)
        # Uninstall Old AV        $uninstallLogFile="C:\Temp\$env:computername`_uninstallLogFile.txt"
        msiexec.exe /x $installFile /l*v $uninstallLogFile UNINSTALL_PASSWORD=$uninstallPassword
        # b. Remove/Disable Windows Defender:
        Set-MpPreference -DisableRealtimeMonitoring $true
        Uninstall-WindowsFeature -Name Windows-Defender
        # Restart-Computer
    } -args $localInstallFile,$uninstallPassword    
}

VMWare CVE-2018-3646 Mitigation

Enable ESXi Side-Channel-Aware Scheduler Version 2 (SCAv2) using ESXCLI
  1. SSH to an ESXi host or open a console where the remote ESXCLI is installed
  2. Check the current runtime values by running:
    • esxcli system settings kernel list -o hyperthreadingMitigation and esxcli system settings kernel list -o hyperthreadingMitigationIntraVM
  3. To enable the ESXi Side-Channel-Aware Scheduler Version 1 run these commands:
    • esxcli system settings kernel set -s hyperthreadingMitigation -v TRUE
    • esxcli system settings kernel set -s hyperthreadingMitigationIntraVM -v FALSE
  4. Reboot the ESXi host for the configuration change to go into effect:
    • Default Method:
      • Get List of running VMs: esxcli vm process list
      • Kill VMs: esxcli vm process kill -type=[soft|hard|force] -world-id=[worldid]
    • Alternative method:
      • List all vms: vim-cmd vmsvc/getallvms
      • vim-cmd vmsvc/power.shutdown [vmid]
      • reboot -d 300 -f

How to Disable SELINUX on CentOS 8

SELinux is a sort of system-call firewall, where processes are in their run spaces. When a daemon tries to access resources outside of their contexts, such as network client ‘named’ process trying to access /home/SOMEUSER directory. That’s out of scope of such daemon; hence, such behaviors would be blocked by SELinux to mitigate potential system-wide attacks. In theory, this is great. However, it takes much efforts to properly tune SELinux to allow processes to run properly. The easy answer from lazy admins is to ‘just turn it off’ to reserve an engineer’s attention on more urgent matters than troubleshooting errors.

# Set SELinux to permissive for this current runtime
# In this mode, policies will not be enforced, but violations will be logged and a warning triggered.

sudo setenforce 0 # same as 'sudo setenforce Permissive'
# Check its status
sestatus
[root@linux1 testadmin]# sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: disabled
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 31
# Make changes to SELinux config file to turn off SELinux upon reboot
sudo sed 's/SELINUX=enforcing/SELINUX=disabled/' -i /etc/selinux/config
# Optional: reboot for changes to take effect
# sudo shutdown -r now

Windows Firewall Block ICMP Ping

Following is a quick exercise in configuring Windows firewall to block certain protocols:

# Disable Ping Outbound
New-NetFirewallRule -DisplayName "Block Outbound ICMPv4" -Direction Outbound -Protocol ICMPv4 -IcmpType 8 -Action Block

# New-NetFirewallRule -DisplayName "Block Outbound ICMPv6" -Direction Outbound -Protocol ICMPv6 -IcmpType 8 -Action Block
# Reverse the change
netsh advfirewall firewall delete rule name="Block Outbound ICMPv4"

# netsh advfirewall firewall delete rule name="Block Outbound ICMPv6"

How to Fix Duplicate Computer Account Names Issue in Active Directory

Automatic cleanup:

# disableDuplicateComputers.ps1
# Version 0.0.1

$defaultPasswordPeriod=30
$disabledComputersReport='c:\disabledComputersReport.csv'
function disableDuplicateComputers{
    param(
        $lastLogonDaysExceeding=30,
        $disabledComputersReport='c:\disabledComputersReport.csv'
        )
    # Obtain duplicates within the domain
    function getDuplicateComputerNames{
        try{
            import-module activedirectory
            $computers=Get-ADComputer -Filter * -properties Name,LastLogonDate,Created,DistinguishedName,SamAccountName,SID|select Name,LastLogonDate,Created,DistinguishedName,SamAccountName,SID,Enabled
            $groups=$computers|Group-Object -Property {$_.name}|?{$_.Count -ge 2}
            write-host "$($groups.count) duplicating groups found." -ForegroundColor Green
            if($groups){
                $duplicates=$groups|Select-Object -ExpandProperty Group|sort name                
                write-host $($duplicates|select SamAccountName,LastLogonDate,DistinguishedName|ft|out-string)
                return $duplicates
            }else{
                return $null
            }
        }catch{
            write-warning $_
            return $null
        }
    }
    write-host "Discovering duplicates in $env:userdnsdomain..."
    $duplicateComputers=getDuplicateComputerNames
    if($duplicateComputers){
        # Selecting expired duplicates
        $daysRange = (get-date).adddays(-$lastLogonDaysExceeding)            
        $duplicateComputersPastXDays=$duplicateComputers|?{$_.lastlogondate -le $daysRange}
        if($duplicateComputersPastXDays){
            # Disabling dups
            $output=($duplicateComputersPastXDays|select SamAccountName,LastLogonDate,DistinguishedName|ft|out-string).trim()
            write-host "These are duplicate computer accounts that have not login past 30 days:`r`n$output" 
            $disabledComputers=@()
            $duplicateComputersPastXDays|%{
                try{
                    if($_.Enabled){
                        Disable-ADAccount -Identity $_.SamAccountName
                        write-host "$($_.SamAccountName) $($_.DistinguishedName) disabled."
                        $disabledComputers+=$_
                    }else{
                        write-host "$($_.SamAccountName) has already been disabled."
                    }
                }catch{
                    write-warning $_
                }
            }
            $parentFolder=split-path $disabledComputersReport -parent    
            if($disabledComputers){
                try{
                    if(!(test-path $parentFolder)){
                        new-item $parentFolder -Type Directory -Force
                    }
                    $disabledComputers|Export-Csv -Path $disabledComputersReport -NoTypeInformation
                    return $true
                }catch{
                    Write-Warning $_
                    return $false
                }
            }else{
                write-host "No computers were disabled during this run."
            }
        }else{
            write-host "Although there are duplicates, none has passed the $lastLogonDaysExceeding threshold. Thus, no computer accounts were disabled."
        }
    }else{
        write-host "There are currently no duplicates in $env:userdnsdomain"
        return $true
    }
}

disableDuplicateComputers $defaultPasswordPeriod $disabledComputersReport

Manual cleanup:

  1. Find duplicate computer names in Active Directory
    # Obtain duplicates within the domain
    function getDuplicateComputerNames{
    $computers=Get-ADComputer -Filter * -properties Name,LastLogonDate,Created,DistinguishedName,SamAccountName,SID|select Name,LastLogonDate,Created,DistinguishedName,SamAccountName,SID
    $groups=$computers|Group-Object -Property {$_.name}|?{$_.Count -ge 2}
    $duplicates=$groups|Select-Object -ExpandProperty Group|sort name
    write-host "$($groups.count) duplicating groups found."
    return $duplicates
    }
    $result=getDuplicateComputerNames

    # Write just the important info
    write-output $result|select SamAccountName,LastLogonDate,DistinguishedName|ft

    # Output all collected info
    write-output $result|ft

    # Optional: export out to CSV
    $duplicateComputersReport='c:\duplicateComputersReport.csv'
    $result|Export-Csv -Path $duplicateComputersReport -NoTypeInformation
    $searchBase='DC=kimconnect,DC=com'
    $duplicateComputersReport='c:\duplicateComputersReport.csv'
    $computers=Get-ADComputer -Filter * -SearchBase $searchbase -Properties Created|Select-Object -Property Name, Created,DistinguishedName,SamAccountName,SID
    $duplicates=$computers|Group-Object -Property {$_.name}|?{$_.Count -ge 2}|Select-Object -ExpandProperty Group
    if(test-path $duplicateComputersReport){
    $duplicates|Export-Csv -Path $duplicateComputersReport -NoTypeInformation
    }else{
    write-host ($duplicates|ft|out-string).trim()
    }
  2. Get the computer SID of each PC
    By default, the results collected above should assist Administrators in determining which computer account has not contacted its Domain Controller for a password change after the default period of 30 days. Those would most likely be ‘duplicate’ accounts. Moreover, the ‘SamAccountName’ value could also indicate that a computer is, in fact a duplicate. One should exercise best judgement when purging AD accounts. Here are some follow-through options:
    # Display duplicate computer accounts that have not login past 30 days
    $lastLogonDaysExceeding = 30
    $daysRange = (get-date).adddays(-$lastLogonDaysExceeding)
    $duplicateComputers=$result|?{$_.lastlogondate -le $daysRange}
    write-output $duplicateComputers|select SamAccountName,LastLogonDate,DistinguishedName|ft
    Sample Output
    SamAccountName LastLogonDate DistinguishedName
    -------------- ------------- -----------------
    $DUPLICATE-18400 3/26/2020 2:04:24 PM CN=testpc007,OU=TEST1,DC=kimconnect
    testpc007$ 10/29/2020 8:23:35 AM CN=testpc007,CN=TEST2,DC=kimconnect
    $DUPLICATE-19008 4/1/2020 12:45:02 PM CN=testpc008,OU=TEST1,DC=kimconnect
    testpc008$ 4/1/2020 12:45:02 PM CN=testpc008,OU=TEST2,DC=kimconnect
    $DUPLICATE-19009 4/1/2020 12:32:45 PM CN=testpc009,OU=TEST1,DC=kimconnect
    testpc009$ 4/1/2020 12:32:45 PM CN=testpc009,OU=TEST2,DC=kimconnect
    Disable all duplicate computer accounts shown above
    $duplicateComputers|%{
    try{
    Disable-ADAccount -Identity $_.SamAccountName
    write-host "$($_.SamAccountName) $($_.DistinguishedName) disabled."
    }catch{
    write-warning $_
    }
    }
    a. Test disable computer account(s) in AD and logon to each machine to see if it still works
    Expected result of mistakenly disabling a valid computer account:


    b. Unjoin each machine from AD > remove the remaining duplicate computer account > rejoin computer back to AD
    c. Get the current computer SID – This method doesn’t work because the SID in AD would not match one retrieved from each localhost
    function getLocalhostSid{
    $localhostSid = Get-WmiObject -Query "SELECT SID FROM Win32_UserAccount WHERE LocalAccount = 'True'" |Select-Object -First 1 -ExpandProperty SID
    $machineSid = ($p = $localhostSid -split "-")[0..($p.Length-2)]-join"-"
    #return New-Object System.Security.Principal.SecurityIdentifier -ArgumentList $machineSid
    return $machineSid
    }
    getLocalhostSid
    function getSid
    {
    $localAdmin = new-object System.Security.Principal.NTAccount('Administrator')
    $rawSid=$localAdmin.Translate([System.Security.Principal.SecurityIdentifier] ).toString()
    return $rawSid.Substring(0,$rawSid.Length-4)
    # return ((Get-LocalUser | Select-Object -First 1).SID).AccountDomainSID.ToString()
    }
    getSid
    # Use Systernals
    psgetsid.exe
    (Get-WmiObject -class Win32_UserAccount -computername $env:computername)[0]

How to Install & Configure Pihole on Ubuntu 20.04

1. Installation
– Run these commands:

# sudo apt-get install gamin -y
sudo curl -sSL https://install.pi-hole.net | bash

– Possible problem: lighttpd service not running (when gamin has not been preinstalled)
– Fix: run these commands

sudo pihole uninstall
rambo@pihole:~$ sudo pihole uninstall
[?] Are you sure you would like to remove Pi-hole? [y/N] y
[✓] Root user check
[✓] Update local cache of available packages
[i] Existing PHP installation detected : PHP version 7.4.3
[i] Be sure to confirm if any dependencies should not be removed
[i] The following dependencies may have been added by the Pi-hole install:
dhcpcd5 git iproute2 whiptail dnsutils cron curl iputils-ping lsof netcat psmisc sudo unzip wget idn2 sqlite3 libcap2-bin dns-root-data libcap2 lighttpd php7.4-common php7.4-cgi php7.4-sqlite3 php7.4-xml php7.4-json php7.4-intl
[?] Do you wish to go through each dependency for removal? (Choosing No will leave all dependencies installed) [Y/n] n
[✓] Removed Web Interface
[✓] Removed /etc/cron.d/pihole
[✓] Removed lighttpd configs
[✓] Removed config files
[i] Removing pihole-FTL...Failed to stop pihole-FTL.service: Unit pihole-FTL.service not loaded.
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt purge lighttpd -y
#sudo pihole -r
#useradd -G pihole pihole
sudo apt-get install gamin -y
curl -sSL install.pi-hole.net | sudo bash
2. Follow the wizard to complete the installation

Hint: simply by pressing enter or <ok >repeatedly until reaching this screen

3. Configure firewall
# Adding firewall rules per pihole prerequites https://docs.pi-hole.net/main/prerequisites/
#sudo iptables -I INPUT -p tcp --dport 53 -j ACCEPT
#sudo iptables -I INPUT -p udp --dport 53 -j ACCEPT
#sudo iptables -I INPUT -p udp --dport 67 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4711 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4712 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4713 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4714 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4715 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4716 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4717 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4718 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4719 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 4720 -j ACCEPT
sudo ip6tables -I INPUT -p udp --dport 547 -j ACCEPT

# DHCP Server:
sudo iptables -I INPUT -p tcp --dport 67 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 67 -j ACCEPT

# DHCP client/relay
sudo iptables -I INPUT -p tcp --dport 68 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 68 -j ACCEPT

# DHCP Failover partners
sudo iptables -I INPUT -p tcp --dport 647 -j ACCEPT

# DNS
sudo iptables -I INPUT -p tcp --dport 53 -j ACCEPT

# Grant Pihole TCP:53 access to localhost
sudo iptables -A INPUT -s 127.0.0.0/8 -p tcp -m tcp --dport 53 -j ACCEPT

# Allowing a traffic from a certain subnet
iptables -A INPUT -s 10.10.10.0/22 -j ACCEPT
# iptables -D INPUT -s 10.10.10.0/22 -j ACCEPT # Reverse previous command

# Save firewall rules
sudo sh -c "iptables-save > /etc/iptables/rules.v4"
sudo sh -c "ip6tables-save > /etc/iptables/rules.v6"
# Fixing startup conflicts between iptables & netfilter-persistent
# sudo systemctl edit netfilter-persistent.service
vim /etc/systemd/system/netfilter-persistent.service.d/iptables.conf
### Verify this content ###
[Unit]
Conflicts=iptables.service ip6tables.service

### Modify content and save file ###
[Unit]
After=iptables.service ip6tables.service ufw.service
4. Check service status
rambo@pihole:~$ service lighttpd status
● lighttpd.service - Lighttpd Daemon
Loaded: loaded (/lib/systemd/system/lighttpd.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2020-12-04 22:43:12 PST; 10min ago
Main PID: 32359 (lighttpd)
Tasks: 6 (limit: 4615)
Memory: 10.0M
CGroup: /system.slice/lighttpd.service
├─32359 /usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf
├─32393 /usr/bin/php-cgi
├─32396 /usr/bin/php-cgi
├─32397 /usr/bin/php-cgi
├─32398 /usr/bin/php-cgi
└─32399 /usr/bin/php-cgi

Dec 04 22:43:12 pihole systemd[1]: Starting Lighttpd Daemon...
Dec 04 22:43:12 pihole systemd[1]: Started Lighttpd Daemon.
rambo@pihole:~$ service pihole* status
● pihole-FTL.service - LSB: pihole-FTL daemon
Loaded: loaded (/etc/init.d/pihole-FTL; generated)
Active: active (exited) since Fri 2020-12-04 22:43:14 PST; 18min ago
Docs: man:systemd-sysv-generator(8)
Process: 32518 ExecStart=/etc/init.d/pihole-FTL start (code=exited, status=0/SUCCESS)

Dec 04 22:43:14 pihole systemd[1]: Starting LSB: pihole-FTL daemon...
Dec 04 22:43:14 pihole pihole-FTL[32518]: Not running
Dec 04 22:43:14 pihole su[32536]: (to pihole) root on none
Dec 04 22:43:14 pihole su[32536]: pam_unix(su:session): session opened for user pihole by (uid=0)
Dec 04 22:43:14 pihole su[32536]: pam_unix(su:session): session closed for user pihole
Dec 04 22:43:14 pihole systemd[1]: Started LSB: pihole-FTL daemon.
5. Configuration
  • Pihole Control Panel:
    http://piholeServerIp/admin
  • Ad Lists:
    https://firebog.net
    https://hosts.oisd.nl
    https://github.com/mmotti/pihole-regex/blob/master/regex.list
  • Test
    dig @<piholeServerIp> blockedsite.com
  • Flush dns
    sudo systemd-resolve --flush-caches # Ubuntu
    service nscd restart # Redhat
    ipconfig /flushdns # Windows
  • Blacklist – regex blocks
    Youtube ads: .*sn-\S{4,}-\S{4,}\.googlevideo\.com
    Youtube.com: (\.|^)(youtu\.?be.*|googlevideo\.com)$
  • Change admin password
    sudo pihole -a -p
6. Troubleshooting
  • Issue: ‘DNS Service Not Running’
    Resolution 1: pihole checkout master
    Resolution 2: re-install pihole
      – Backup: pihole -a teleporter
      – Move backup file: copy the tar.gz file from current directory $(pwd)/*.tar.gz to desktop where Internet browser is available for the restoring step
      – Uninstall: pihole uninstall
      – Reinstall: sudo apt install pihole
      – Restore settings: Login into Pi-hole > Settings > Teleporter > Under Restore, click Choose File > pick the backup file in tar.gz format > open > click Restore > OK
    Resolution 3: 
     – Run debug: pihole -d
     – Grant Pihole TCP:53 access to localhost: sudo iptables -A INPUT -s 127.0.0.0/8 -p tcp -m tcp --dport 53 -j ACCEPT
    Resolution 4: Set the watchservice script to ensure that pihole is running at all times
  • Issue: unable to reach server via port 80
    Resolution: sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
  • Issue: Pihole service crashes at random times
    Resolution: create a service watcher script
7. How to create a Backup via command line:
cd ~/Desktop
pihole -a teleporter
ls ~/Desktop

How to Block Distracting Sites Such as Youtube and Hulu on Your Home Network

Overview:
  • – You send a voice command ‘block youtube’ to Alexa, an Amazon personal assistant device
  • – Alexa relays that command to IFTTT.com
  • – IFTTT triggers a web call to your local Domain Name Server (DNS) server called ‘pihole’
  • – This web call must be configured at the router/firewall to pass traffic from IFTTT though the firewall to the your local pihole server
  • – Pihole receives the request and triggers blockyoutube.sh
  • – Blockyoutube.sh contains the urls and ips of youtube.com that will configure pihole to delete any name to ip translation related to youtube.com
  • – A set of computers on your network shall be configured to use the local ‘pihole’ server as its DNS
  • – This can be setup at the Dynamic Host Control Protocol (DHCP) server
  • – DHCP is often a function of the firewall or smart wireless devices such as Ubiquiti Unifi Controllers and Access Points
  • – This DHCP tells all computers on the network what IP and DNS each should use
  • – When a user computer asks its DNS server (pihole) about youtube.com, pihole will say ‘no where’
  • – Youtube.com is effectively blocked on local computers via your voice command
Illustration:
  • To be documented…

PowerShell: Check Speculation Controls for Spectre Mitigation Support on Windows

Run the below function to view an output similar to this:

BTIHardwarePresent : True -> apply OEM BIOS/firmware update
BTIWindowsSupportPresent : True -> install January 2018 update
BTIWindowsSupportEnabled : True -> On server, follow guidance https://support.microsoft.com/help/4072698
BTIDisabledBySystemPolicy : False -> ensure not disabled by policy. False is expected
BTIDisabledByNoHardwareSupport : False -> ensure OEM BIOS/firmware update is applied.
BTIKernelRetpolineEnabled : True
BTIKernelImportOptimizationEnabled : True
KVAShadowRequired : True -> no action, this is a function of the CPU the computer uses
KVAShadowWindowsSupportPresent : True -> install January 2018 update
KVAShadowWindowsSupportEnabled : True -> On server, follow guidance https://support.microsoft.com/help/4072698
KVAShadowPcidEnabled : True -> no action , this is a function of the CPU the computer uses
SSBDWindowsSupportPresent : True -> install Windows updates as documented in adv180012 https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV180012
SSBDHardwareVulnerable : True
SSBDHardwarePresent : True -> install BIOS/firmware update with support for SSBD from your device OEM
SSBDWindowsSupportEnabledSystemWide : False -> follow recommended actions to turn on SSBD https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV180012

Source: https://support.microsoft.com/en-us/help/4073119/protect-against-speculative-execution-side-channel-vulnerabilities-in

function checkSpeculationControls($computer=$env:computername){
    $command={
        # Interpretations of output: https://support.microsoft.com/en-us/help/4074629/understanding-the-output-of-get-speculationcontrolsettings-powershell
        #$originalExecutionPolicy = Get-ExecutionPolicy
        #Set-ExecutionPolicy RemoteSigned -Scope Currentuser
        if(!(Get-command Get-SpeculationControlSettings -ea SilentlyContinue)){
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            if(!(Get-Module nuget)){
                Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
            }
            Install-Module SpeculationControl -force
        }
        #Set-ExecutionPolicy $originalExecutionPolicy -Scope Currentuser
        return Get-SpeculationControlSettings
    }
    invoke-command -ComputerName $computer -ScriptBlock $command
}

Domain Controller Vulnerability Scan for ZeroLogon VCE-2000-1472

function vce2020-1472{
    # Source: https://github.com/cisagov/cyber.dhs.gov/tree/master/assets/report/ed-20-04_script
    # Original script has been modified to fix a couple of bugs with connection error detection
    # Create output directory on executiong user's desktop
    $date = get-date -Format MMddyyyy
    $rootPath = $env:USERPROFILE + '\Desktop\CISA'
    $fullPath = $rootPath + '\' + $date
    $UpdateList = $fullPath + '\complianceReport.csv'
    if (Test-Path $rootPath){
        if (!(test-path $fullPath)){
                mkdir $fullPath
            }
    }else{
        mkdir $fullPath
        }

        function checkPort{
            Param(
                [string]$server,
                [int]$port=135,
                [bool]$verbose=$true
                )
         
                function importPortQry{
                    if (!(Get-Command portqry.exe -ErrorAction SilentlyContinue)){
                        if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
                        Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))}
                        choco install portqry -y
                        if (Get-Command portqry.exe -ErrorAction SilentlyContinue){return $true}else{return $false}
                    }else{
                        return $true
                    }
                }
                 function Check-NetConnection($server, $port) {
                    $session = New-Object System.Net.Sockets.TcpClient;
                    $result=$false
                    try {
                        $session.Connect($server, $port);
                        $result=$true;
                    } catch {
                        $result=$false;
                    } finally {
                        $session.Close();
                        
                    }
                    return $result;
                }        
        
            function testPortArray {
                # Casting parameters is better than passing arguments as that allows for switches that can be arranged in any order
                param ([string]$targetServer,[array]$arrPorts,$verbose=$false)
                $source = $env:computername
                $destination=$targetServer.toUpper()
                $portsCount=$arrPorts.count
                $portsSuccess=0
        
                foreach ($port in $arrPorts){        
                    $testResult = Check-NetConnection -server $targetServer -port $port;
                    If ($testResult){
                        if($verbose){Write-Output "$port`: reachable"}
                        $portsSuccess++
                        }
                    Else{
                        if($verbose){Write-Output "$port`: unreachable"}
                        }
                }
        
                if($portsCount -eq $portsSuccess){
                    return $true
                }else{
                    return $false
                }
        
            }
             
            if($verbose){write-host "Checking for existence of PortQry.exe..."}
            do {
                $portQryExists=Get-Command "PortQry.exe" -ErrorAction SilentlyContinue
                if(!$portQryExists){
                    importPortQry;
                    sleep 1;
                }
            }while(!$portQryExists)
        
            $portReachable=Check-NetConnection -server $server -port $port     
            if ($portReachable){
                if($verbose){write-host "$env:computername is able to reach $server on the primary port of $port."}
                $strInvokeCommand = "PortQry.exe -e $port -n $server";
                $arrQuryResult = Invoke-Expression $strInvokeCommand;
             
                $arrPorts = @();    #Initiates and clears the collection of ports array
                ForEach ($strResult in $arrQuryResult)
                {
                  If ($strResult.Contains("ip_tcp"))
                  {
                  $arrSplt = $strResult.Split("[");
                  $strPort = $arrSplt[1];
                  $strPort = $strPort.Replace("]","");
                  $arrPorts += $strPort;
                  }
                }
         
                #  Remove duplicate port records from within the array
                $arrPorts = $arrPorts | select -uniq
                if ($arrPorts){            
                    if($verbose){write-host "These are the detected dynamic ephemeral ports being used:`r`n$arrPorts"  }      
                    $result=testPortArray -targetServer $server -arrPorts $arrPorts #  Pass the ports array into the workflow as a parameter
                    return $result
                }else{
                    if($verbose){write-host "Ephemeral ports were NOT detected.`r`n"}
                        return $portReachable
                        }
            }else{
                if($verbose){write-host "$env:computername is NOT able to reach $server on port: $port`r`n"}
                return $false
                }
        }

    ## Get all DCs in forest
    $allDCs = ($((Get-ADForest).Domains | %{ Get-ADDomainController -Filter * -Server $_ })).hostname
    $validHotFixes=@(
        'KB4571729',
        'KB4571719',
        'KB4571736',
        'KB4571702',
        'KB4571703',
        'KB4571723',
        'KB4571694',
        'KB4565349',
        'KB4565351',
        'KB4566782',
        'KB4577051',
        'KB4577038',
        'KB4577066',
        'KB4577015',
        'KB4577069',
        'KB4574727',
        'KB4577062',
        'KB4571744',
        'KB4571756',
        'KB4571748',
        'KB4570333'
    )
    Write-Host -ForegroundColor White ("There are $($allDcs.count) DCs")

    ## Foreach DC, get Component Based Servicing provided updates and MSI installed updates. Then dump to a common CSV
    foreach ($dc in $allDCs) {
        $winRmIsAvailable=Test-NetConnection $dc -commonTCPPort WinRm -informationlevel Quiet
        $rpcIsAvailable=checkPort $dc -port 135 -verbose $false
        
        if($rpcIsAvailable){
            $OS = $(Get-WmiObject -ComputerName $DC -Class Win32_OperatingSystem).caption
            Write-Host -ForegroundColor White ("Getting updates for $DC")
            Write-Host -ForegroundColor White ("Checking CBS Updates...")
            try{
                $quickFixes=Get-WmiObject Win32_quickfixengineering -ComputerName $dc | Select-Object *
            }catch{
                write-warning $_
            }
            if($quickFixes){
                $quickFixes|%{
                    $hotfix=$_.HotFixID 
                    if($hotfix -in $validHotFixes){
                        $hotfixFound=$true
                        $CBSObj = New-Object -TypeName psobject
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $DC
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $OS
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "Update" -Value $hotfix
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $hotfixFound
                        $CBSObj | Export-Csv -path $UpdateList -Append -NoTypeInformation                
                        #break;
                    }
                }
            }
        }elseif($winRmIsAvailable){
            Write-Host -ForegroundColor White ("Getting updates for $dc`r`nChecking MSI Updates...")
            $session=new-pssession -ComputerName $dc
            if($session){
                $x=Invoke-Command -session $session -ScriptBlock { 
                        $updatesession = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session",$env:computername))
                        $UpdateSearcher = $updatesession.CreateUpdateSearcher()
                        $searchresult = $updatesearcher.Search("IsInstalled=1").Updates|select Title
                        #$updatesSession = New-Object -ComObject Microsoft.Update.Session ;
                        #$updateSearch = $updatesSession.CreateUpdateSearcher();
                        #$hotfixes=$updateSearch.Search("IsInstalled=1").Updates | Select Title;
                        <#
                        Exception calling "Search" with "1" argument(s): "Exception from HRESULT: 0x8024401C"
                        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
                        + FullyQualifiedErrorId : ComMethodTargetInvocation
                        + PSComputerName        : TESTSERVER
                        #>
                        $os=(Get-WmiObject -Class Win32_OperatingSystem).caption;
                        return @($os,$searchresult)
                    }
                remove-pssession $session
                $hotfixCount=0
                $x[1] | ForEach-Object {
                    $Title = $_.Title
                    $kb=switch -Wildcard ($Title){
                        "*4571729*" {"KB4571729"}
                        "*4571719*" {"KB4571719"}
                        "*4571736*" {"KB4571736"}
                        "*4571702*" {"KB4571702"}
                        "*4571703*" {"KB4571703"}
                        "*4571723*" {"KB4571723"}
                        "*4571694*" {"KB4571694"}
                        "*4565349*" {"KB4565349"}
                        "*4565351*" {"KB4565351"}
                        "*4566782*" {"KB4566782"}
                        "*4577051*" {"KB4577051"}
                        "*4577038*" {"KB4577038"}
                        "*4577066*" {"KB4577066"}
                        "*4577015*" {"KB4577015"}
                        "*4577069*" {"KB4577069"}
                        "*4574727*" {"B4574727"}
                        "*4577062*" {"KB4577062"}
                        "*4571744*" {"KB4571744"}
                        "*4571756*" {"KB4571756"}
                        "*4571748*" {"KB4571748"}
                        "*4570333*" {"KB4570333"}                
                    }
                    if($kb){
                        $hotfixCount++
                        $CBSObj = New-Object -TypeName psobject
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $DC
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $x[0]
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "Update" -Value $kb
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $True
                        $CBSObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
                        #break
                    }
                }
                if($hotfixCount -eq 0){
                    $MSIObj = New-Object -TypeName psobject
                    $MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
                    $MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $x[0]
                    $MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'Missing'
                    $MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $false
                    $MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
                }            
            }else{
                write-warning "Unable to connect to $dc via WinRM"
                $MSIObj = New-Object -TypeName psobject
                $MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
                $MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value 'unknown'
                $MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'unknown'
                $MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value 'unknown'
                $MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
            }
        }else{
            write-warning "Unable to connect to $dc via RPC nor WinRM"
            $MSIObj = New-Object -TypeName psobject
            $MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
            $MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value 'unknown'
            $MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'unknown'
            $MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value 'unknown'
            $MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
        }
    }
    Write-Host -ForegroundColor White ("INFORMATION: DONE!")
}

vce2020-1472

RDP Connection Error: CredSSP encryption oracle remediation

The Symptom:

[Window Title]
Remote Desktop Connection

[Content]
An authentication error has occurred.
The function requested is not supported

Remote computer: 1.1.1.1
This could be due to CredSSP encryption oracle remediation.
For more information, see https://go.microsoft.com/fwlink/?linkid=866660

[OK]
The Cause:

There’s this thing called Encryption Oracle Remediation (EOR) that would be installed on the client, server, or both. If the client has the CredSSP update installed, and Encryption Oracle Remediation is set to Mitigated. Then, this client will not allow insecure connections. On the same token, if the server has the CredSSP patched and is set to Force updated clients. That server will block any RDP connection from clients that do not have the CredSSP update installed. Here are the details of these compatibilities.

Interoperability Matrix:

CAUSE
Server
Updated Force updated clients Mitigated Vulnerable
Client Updated Allowed Blocked 2 Allowed Allowed
  Force updated clients Blocked Allowed Allowed Allowed
  Mitigated Blocked 1 Allowed Allowed Allowed
  Vulnerable Allowed Allowed Allowed Allowed

Source: Microsoft

The Solutions:
  • Option 1: patch both clients and servers
  • Option 2: Set the Server EOR to Mitigated
    • Not recommended
  • Option 3: Set the Client to Vulnerable
    • How To Execute ‘Option 3’
REG ADD HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters\ /v AllowEncryptionOracle /t REG_DWORD /d 2

How to Revert ‘Option 3’

Set-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters' -name "AllowEncryptionOracle" 1 -Type DWord

Key value table:

  1. Force Updated Clients
    Registry Hive HKEY_LOCAL_MACHINE
    Registry Path Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters
    Value Name AllowEncryptionOracle
    Value Type REG_DWORD
    Value 0
  2. Mitigated
    Registry Hive HKEY_LOCAL_MACHINE
    Registry Path Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters
    Value Name AllowEncryptionOracle
    Value Type REG_DWORD
    Value 1
  3. Vulnerable
    Registry Hive HKEY_LOCAL_MACHINE
    Registry Path Software\Microsoft\Windows\CurrentVersion\Policies\System\CredSSP\Parameters
    Value Name AllowEncryptionOracle
    Value Type REG_DWORD
    Value 2

Set Windows Remote Desktop To Allow Blank Passwords

By default, Windows restricts RDP access for account without passwords. Of course, this is a security 101 issue. When trying to do so, one should expect to see errors such as this:

Sometimes, Windows savvy users want to bypass that restrict. Well, it’s as simple as copy & paste the following line in PowerShell running as Administrator:

Set-ItemProperty -Path 'REGISTRY::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa' -Name 'LimitBlankPasswordUse' -Value 0 -force

PowerShell: Audit Failed Logins of A User

$username='rambo'

function auditLockouts($userName,$domainController,$refreshMinutes=1){
 
    function getLockouts($domainControler){
        # Requirement:
        # Domain Controllers Audit Group Policy has been enabled via these steps...
        # Browse to computer configuration > Security Settings > Advanced Audit Policy Configuration > Audit Policies >
        # Account Management > Enable success and failure for the “Audit User Account Management” policy.
        if (!(get-command get-aduser -ea silentlycontinue)){
            try{
                Import-Module ServerManager
                Add-WindowsFeature RSAT-AD-PowerShell
                }catch{
                    install-module activedirectory
                    }
            }
 
        if(!$domainControler){$domainControler=(Get-ADDomain).PDCEmulator}
        $dataTimeStamp=get-date
        $lockoutEvents=Get-WinEvent -ComputerName $domainControler -FilterHashtable @{
            LogName = 'Security'
            ID = 4740
            }
        return @($lockoutEvents,$dataTimeStamp)
    }
 
    $principle=Get-ADUser $userName -ea SilentlyContinue    
    if($principle){
        $samAccountName=$principle.SamAccountName
        $firstName=$principle.GivenName
        $lastName=$principle.Surname
        write-host "$username is matched $firstName $lastName "
        $refreshLockoutData=.{if($lockOutDataTimeStamp){(get-date).AddMinutes(-$refreshMinutes) -lt $lockOutDataTimeStamp}else{$true}}
        if (!$lockOuts -or $refreshLockoutData){
            write-host "Scanning $domainController for lockout records... Please wait awhile."
            $lockoutData=getLockouts $domainController
            $GLOBAL:lockOuts=$lockoutData[0]
            $GLOBAL:lockOutDataTimeStamp=$lockoutData[1]
            }
        $thisPersonLockouts=$lockouts|?{$_.Properties[0].Value -eq $samAccountName}
        $results=foreach ($lockout in $thisPersonLockouts){
                    [pscustomobject]@{
                        UserName = $lockout.Properties[0].Value
                        SourceComputer = $lockout.Properties[1].Value
                        TimeStamp = $lockout.TimeCreated
                    }}
        if($results){
            return $results
            }else{
                write-host "No lockout events matched $userName."
                return $null
                }
    }else{
        write-warning "$userName is invalid"
        return $null
        }
}
 
auditLockouts $username
# Sample Output
#PS C:\Windows\system32> auditLockouts rambo       
#rambo        is matched rambo 1982
#
#UserName     SourceComputer TimeStamp
#--------     -------------- ---------
#rambo        JUNGLE01       02/29/1982 5:11:50 PM
#rambo        JUNGLE01       02/29/1982 4:57:07 PM
#rambo        JUNGLE01       02/29/1982 4:46:51 PM
#rambo        JUNGLE01       02/29/1982 4:43:46 PM
#rambo        JUNGLE01       02/29/1982 4:34:05 PM
#rambo        JUNGLE01       02/29/1982 4:29:35 PM
#rambo        JUNGLE01       02/29/1982 4:28:30 PM
#rambo        JUNGLE01       02/29/1982 4:28:09 PM
#rambo        JUNGLE01       02/29/1982 4:26:24 PM
#rambo        JUNGLE01       02/29/1982 4:24:44 PM
#rambo        JUNGLE01       02/29/1982 4:24:14 PM
#rambo        JUNGLE01       02/29/1982 4:13:58 PM
#rambo        JUNGLE01       02/29/1982 4:06:27 PM
#rambo        JUNGLE01       02/29/1982 4:01:07 PM
#rambo        JUNGLE01       02/29/1982 3:50:51 PM
#rambo        JUNGLE01       02/29/1982 3:40:35 PM
#rambo        JUNGLE01       02/29/1982 3:30:19 PM
#rambo        JUNGLE01       02/29/1982 3:20:03 PM
#rambo        JUNGLE01       02/29/1982 3:09:48 PM
#rambo        JUNGLE01       02/29/1982 2:59:32 PM
#rambo        JUNGLE01       02/29/1982 2:49:16 PM

Terminal Service Auditing – Generate Report of RDP Sessions with Certain Login Dates

# getLoginEvents.ps1

function getLoginEvents{
    param(
        $computername=$env:computername,
        $daysLimit=30
        )
    $ErrorActionPreference='stop'    
    try{        
        $logins=Get-WinEvent -ComputerName $ComputerName -LogName "Microsoft-Windows-TerminalServices-LocalSessionManager/Operational"| `
                ?{$_.ID -match '21|25' -and $_.TimeCreated -ge (get-date).AddDays(-$daysLimit)}| `
                Select Id,TimeCreated, Message
        $loginEvents=[System.Collections.ArrayList]::new()
        Foreach ($login in $logins){ 
            $loginTime = $login.TimeCreated
            $eventId=$login.Id
            $loginType=switch ($eventId){
                '21'{'New Session';break}
                '25'{'Reconnection';break}
                }
            $x = $login.Message -split "`n" 
            $user = ($x|Select-Object -Index "2").Substring(6)
            $source=($x|Select-Object -Index "4").Substring(24)       
            $null=$loginEvents.Add([PSCustomObject]@{
                loginTime = $loginTime;
                username = $user;
                loginType=$loginType;
                loginSource = $source;
                })
        }
        return $loginEvents
        }
    catch{
        write-warning "$($error[0])"
        return $null
    }
}
getLoginEvents

# Sample Output
#
#loginTime             username             loginType    loginSource
#---------             ----                 ---------    ---------
#7/3/2020 9:34:35 PM   KIMCONNECT\RAMBO1... Reconnection 192.168.0.127
#7/3/2020 9:34:19 PM   KIMCONNECT\RAMBO1... Reconnection 192.168.0.66
#7/3/2020 8:57:44 PM   KIMCONNECT\RAMBO1... Reconnection 192.168.0.127
#7/3/2020 5:59:24 PM   KIMCONNECT\RAMBO1... Reconnection 192.168.0.66
#7/3/2020 3:42:04 PM   KIMCONNECT\RAMBO1... Reconnection 192.168.0.66
#7/2/2020 9:20:19 PM   KIMCONNECT\RAMBO1... Reconnection 192.168.0.66

PowerShell: Detecting Windows Antivirus

One of the initial tasks of a Windows user is to determine whether a computer has Antivirus enabled. For modern Windows 10 machines, Windows Defender has been doing a good job at protecting client machines. Often, enterprises opt to deploy 3rd party malware and ransomware protection in addition to Microsoft’s default safeguard. This paragraph is getting longer than I’m willing to write non-code stuff. Here goes the work-in-progress scripty for your entertainment and/or refactoring considerations.

# detectWindowsAntivirus.ps1
# Version: 0.0.1
# License: GPLv3
# What this does: you know.

# User provided variables:
$expectedAntivirusNames = "antivirus|endpoint|protection|defender|msmpeng|guard" #Edit this line to include additional antivirus names that are being used in your organization

function detectAntivirus{
    param(
        $computername=$env:computername,
        $keywords="antivirus|endpoint|protection|defender|msmpeng|guard"
        )                 
    
    # First: try to obtain antivirus name from Security Center (this only works for Client OS)
    $antivirusFromSecurityCenter=.{try{
                    $wmiQuery = "SELECT * FROM AntiVirusProduct" 
                    $securityCenter=Get-WmiObject -ComputerName $computername -Namespace "root\SecurityCenter2" -Query $wmiQuery @psboundparameters -ErrorVariable myError -ErrorAction Stop
                    return $securityCenter.displayName             
                    }catch{
                        return $false;
                        }
                }
    if($antivirusFromSecurityCenter){return $antivirusFromSecurityCenter}

    # Second: try to obtain product name from Applications List
    write-host "Unable to detect antivirus in namespace root\SecurityCenter2. Now querying AppWiz.cpl ..."
    $antivirusFromAppwiz=.{try{                        
                                    $appWiz=Get-CimInstance -ClassName win32_InstalledWin32Program -ComputerName $computername -ErrorAction Stop | ?{$_.Name -match $keywords}|%{"$($_.Name)"}
                                    return $appWiz
                                    }
                                catch{
                                    return $false
                                    }
                                }                           
    if ($antivirusFromAppwiz){return $antivirusFromAppwiz}

    # Third: look into the registry
    write-host "Unable to detect antivirus in AppWiz. Now querying registry ..."            
    $antivirusFromRegistry=.{$results=@()
                                    try{
                                        #Get-Service -ComputerName $computername -Name RemoteRegistry | Start-Service
                                        $hive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $computername)
                                        }
                                    catch{
                                        write-host "unable to open remote registry of $computerName"
                                        return $false
                                        }
                                    if ($hive){
                                        $regPathList = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
                                                        "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
                                        foreach($regPath in $regPathList) {
                                            if($key = $hive.OpenSubKey($regPath)) {
                                                if($subkeyNames = $key.GetSubKeyNames()) {
                                                    foreach($subkeyName in $subkeyNames) {
                                                        $productKey = $key.OpenSubKey($subkeyName)
                                                        $productName = $productKey.GetValue("DisplayName")
                                                        $productVersion = $productKey.GetValue("DisplayVersion")
                                                        $productComments = $productKey.GetValue("Comments")
                                                        if (!$productName){$productName="";}
                                                        if (!$productComments){$productComments="";}
                                                        if(($productName.ToLower() -match $keywords) -OR ($productComments.ToLower() -match $keywords)) {                                                            
                                                            #$resultObj = [PSCustomObject]@{
                                                            #    Product = $productName
                                                            #    Version = $productVersion
                                                            #}
                                                            $results+=,$productName
                                                        }
                                                    }
                                                }
                                            }
                                            $key.Close()
                                        }
                                        }
                                    return $results
                                    }
    if ($antivirusFromRegistry){return $antivirusFromRegistry}                                                                                                          
    
    # Finally: return nothing
    write-host "Unable to detect antivirus in registry ..."
    return $false
}   

detectAntivirus localhost $expectedAntivirusNames

PowerShell: Add Windows TrustedHosts Remotely

<# AddTrustedHostsRemote.ps1

Solves this problem:
enter-pssession : Connecting to remote server REMOTESHERVER failed with the following error message : WinRM cannot
process the request. The following error occurred while using Kerberos authentication: Cannot find the computer
OMSVEPIAZU901. Verify that the computer exists on the network and that the name provided is spelled correctly. For
more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ enter-pssession REMOTESHERVER
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (REMOTESHERVER:String) [Enter-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : CreateRemoteRunspaceFailed
#>

# Change this value
$computername="REMOTESHEVER"

# Autogen variables
$trustedHosts="*.$env:USERDNSDOMAIN"
$adminUsername=Read-Host -Prompt 'Input your admin name in this format DOMAIN\UserID';
$password=Read-Host -Prompt "Input the password for $adminUsername" -AsSecureString;
$passwordHash = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password);
$adminPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($passwordHash);

# Enable WinRM Remotely
psexec.exe \\$computername -u $adminUsername -p $adminPassword -s C:\Windows\system32\winrm.cmd qc -quiet

# Add Trusted hosts
$addTrustedHostsRemote="psexec.exe \\$computername -u $adminUsername -p $adminPassword -h -d powershell.exe 'set-item WSMan:\localhost\Client\TrustedHosts -Value $trustedHosts -Concatenate -force'"
Invoke-Expression $addTrustedHostsRemote;

<# Failure Example: this is due to a cross-domain default credential being used
PS C:\Users\kim> Invoke-Expression $addTrustedHostsRemote;

PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

Couldn't access SHERVER:
Access is denied.
#>

<# View trusted hosts: default view
Get-Item WSMan:\localhost\Client\TrustedHosts
PS C:\Users\kim> Get-Item WSMan:\localhost\Client\TrustedHosts
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client
Type Name SourceOfValue Value
---- ---- ------------- -----
System.String TrustedHosts

# Set view
C:\Windows\system32> Get-Item WSMan:\localhost\Client\TrustedHosts


WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client

Type Name SourceOfValue Value
--- ---- ------------- -----
System.String TrustedHosts *.kimconnect.local,10.10.0.*
#>

<# Set Trusted Hosts
$trustedHosts="*.domain.local"
set-item WSMan:\localhost\Client\TrustedHosts -Value $trustedHosts -Concatenate -force

set-item : Access is denied.
At line:1 char:1
+ set-item WSMan:\localhost\Client\TrustedHosts -Value $trustedHosts -C ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Set-Item], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.SetItemCommand

Set-ItemProperty –Path "REGISTRY::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" –Name LocalAccountTokenFilterPolicy –Value 1 -Type DWord
PS C:\Users\kim> Set-ItemProperty –Path "REGISTRY::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" –Na
me LocalAccountTokenFilterPolicy –Value 1 -Type DWord
Set-ItemProperty : Requested registry access is not allowed.
At line:1 char:1
+ Set-ItemProperty –Path "REGISTRY::HKLM\SOFTWARE\Microsoft\Windows\Cur ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (HKLM\SOFTWARE\M...Policies\System:String) [Set-ItemProperty], Securit
yException
+ FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShell.Commands.SetItemPropertyCommand

Resolution: Run-Powershell as Administrator on the remote host

# Other things:
$clientSubnet="10.10.10.*" # Corresponds to 10.10.10.0/24 subnet
set-item WSMan:\localhost\Client\TrustedHosts -Value $clientSubnet -Concatenate -force
get-item WSMan:\localhost\Client\TrustedHosts

Enter-PSSession -Credential "$env:USERDNSDOMAIN\Administrator" localhost # This works as elevated admin session; perhaps, due to the built-in hard-coding of its ssid
#>

<# Accessing WinRM cross-domain
$adminUser="kimconnect.net\baloo"
$remoteSherver="SHEVER009.kimconnect.net"
enter-pssession $remoteSherver -Credential $adminUser
#>