Windows: Disable Automatic Restart After Updates

1. Run gpedit.msc as Administrator
2. Navigate to Local Group Policy Editor > Computer Configuration > Administrative Templates > Windows Components > Windows Update
3. Double-click on “No auto-restart with automatic installations of scheduled updates”
4. Select “Enabled”, and then click “OK”
5. Close the local group policy editor

PowerShell: Unjoin Computer From Domain

$computername='testwindows'
$adminUsername='intranet\testadmin'
$adminPassword='PASSWORD'
$workgroup='Archive'

function unjoinComputerFromDomain{
    param(
        $computername,
        $adminUsername,
        $adminPassword,
        $workgroup='Archive'
        )
  $adminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $adminUsername,$(ConvertTo-SecureString $adminPassword -AsPlainText -Force)
  $psSession=try{
    $psOptions=New-PSSessionOption -OpenTimeout 300 -CancelTimeout 300
    new-pssession -computername $computername -Credential $adminCred -SessionOption $psOptions
    write-host "Connected to $computername..."
  }catch{
    write-warning $_
    $false
  }
  if($psSession.State -eq 'Opened'){
    try{
        $result=invoke-command -session $psSession -scriptblock{
            param ($adminUsername,$adminPassword,$workgroup)
            if ((gwmi win32_computersystem).partofdomain -eq $true) {
                $userdomain=$env:USERDNSDOMAIN
                $encryptedPassword=$(ConvertTo-SecureString $adminPassword -AsPlainText -Force)
                Set-LocalUser -name Administrator -Password $encryptedPassword
                write-host "The local 'Administrator' account password has been reset to be the same as the password of user $adminUsername"
                $adminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $adminUsername,$encryptedPassword
                try{
                    Remove-Computer -UnjoinDomaincredential $adminCred -PassThru -Verbose -Restart -WorkgroupName $workgroup -Force
                    write-host "$env:computername has been removed from $userdomain"
                    return $true
                }catch{
                    write-warning $_
                    return $false
                }
            }else{
                write-host "$env:computer is NOT joined to any domain. No actions taken."
                return $true
            }      
        } -Args $adminUsername,$adminPassword,$workgroup -EA Stop
        $nullRemove-PSSession -ID $psSession.ID
        return $result
    }catch{
        write-warning $_
        $null=Remove-PSSession $psSession
        return $false
    }    
  }else{
    write-host "Unable to connect to $computername..."
    return $false
  }
}

unjoinComputerFromDomain $computername $adminUsername $adminPassword

Windows Server 2019 Remote Desktop Black Screen Problem

While there’s no definite solution to this issue, here are some options to work around this problem:

Option A:

  • Change the Screen Resolution slightly each time before clicking Connect
  • Disable bitmap caching for your RDP connections
  • Confirm that the target machine’s video drivers are up to date
  • Add the login account into the local Administrators group to test
  • Use a different RDP client (e.g. Remmina, mRemoteNG), instead of Windows’ default MSTSC.

Option B:

  • Install the latest Windows Updates
  • Reinstall the Server’s OS
  • If all else fails, hire guys like me to fix it

PowerShell: Function to Get Group Members as a Bypass Orphanated SID Errors

Problem:

[TESTSERVER]: PS C:\Users\administrator> Get-LocalGroupMember 'Remote Desktop Users'

Get-LocalGroupMember : Failed to compare two elements in the array.
    + CategoryInfo          : NotSpecified: (:) [Get-LocalGroupMember], InvalidOperationException
    + FullyQualifiedErrorId : An unspecified error occurred.,Microsoft.PowerShell.Commands.GetLocalGroupMemberCommand

[TESTSERVER]: PS C:\Users\administrator> Add-LocalGroupMember -group 'Remote Desktop Users' -member intranet\testuser
Add-LocalGroupMember : Principal intranet\testuser was not found.
    + CategoryInfo          : ObjectNotFound: (portal\nbsingh:String) [Add-LocalGroupMember], PrincipalNotFoundExcepti
   on
    + FullyQualifiedErrorId : PrincipalNotFound,Microsoft.PowerShell.Commands.AddLocalGroupMemberCommand

Workaround:

$servers = "localhost"
$groupName = 'Remote Desktop Users'

function getGroupMembers{
  param(
    $servers='localhost',
    $groupName='Administrators'
  )
  $members=@()
  foreach ($server in $servers){
      $group = [ADSI]"WinNT://$Server/$groupName"
      $groupMembers = @($group.Invoke('Members') | ForEach-Object {([ADSI]$_).path})
      $members+=$groupMembers
  }
  return $members
}

getGroupMembers $servers $groupName

PowerShell: Check RPC Reachability of Remote Computer

# This is an ancient script that would work with PowerShell versions 2 to 5, but it won't work with version 6

  function checkRpc($server){
    #  WORKFLOW QUERIES THE PASSED ARRAY OF PORTS TO DETERMINE STATUS
    workflow Check-Port {
    param ([string[]]$RPCServer,[array]$arrRPCPorts)
    $comp = hostname

    ForEach -parallel ($RPCPort in $arrRPCPorts){
    $bolResult = InlineScript{Test-NetConnection -ComputerName $Using:RPCServer -port $Using:RPCPort -InformationLevel Quiet}
    If ($bolResult){
    Write-Output "$RPCPort on $RPCServer is reachable"
    }Else{
    Write-Output "$RPCPort on $RPCServer is unreachable"
    }
    }
    }
    #  INITIAL RPC PORT
    $strRPCPort = "135"
    #  MODIFY PATH TO THE PORTQRY BINARY IF NECESSARY
    $strPortQryPath = "C:\Sysinternals"
    #  TEST THE PATH TO SEE IF THE BINARY EXISTS
    If (get-command portqry.exe){
    $strPortQryCmd = "PortQry.exe -e $strRPCPort -n $Server"
    }Else{
    Write-Output "Could not locate Portqry.exe"
    Exit
    }
    #  CREATE AN EMPTY ARRAY TO HOLD THE PORTS RETURNED FROM THE RPC PORTMAPPER
    $arrPorts = @()
    #  RUN THE PORTQRY COMMAND TO GET THE EPHEMERAL PORTS
    $arrQuryResult = Invoke-Expression $strPortQryCmd
    # CREATE AN ARRAY OF THE PORTS
    ForEach ($strResult in $arrQuryResult)
    {
    If ($strResult.Contains("ip_tcp"))
    {
    $arrSplt = $strResult.Split("[")
    $strPort = $arrSplt[1]
    $strPort = $strPort.Replace("]","")
    $arrPorts += $strPort
    }
    }
    #  DE-DUPLICATE THE PORTS
    $arrPorts = $arrPorts | Sort-Object |Select-Object -Unique
    #  EXECUTE THE WORKFLOW TO CHECK THE PORTS
    Check-Port -RPCServer $Server -arrRPCPorts $arrPorts
  }

checkRpc remotecomputername

Quick Command To Get Windows Version

To Get Windows Version as String:
(Get-WmiObject -class Win32_OperatingSystem).Caption
[deesee1]: PS C:\Users\kimconnect> (Get-WmiObject -class Win32_OperatingSystem).Caption

Microsoft Windows Server 2012 R2 Standard
To Get Windows Version as Release Number:
[System.Environment]::OSVersion
[deesee1]: PS C:\Users\kimconnect> [System.Environment]::OSVersion

Platform ServicePack Version VersionString
-------- ----------- ------- -------------
Win32NT 6.3.9600.0 Microsoft Windows NT 6.3.9600.0

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>

PowerShell: Create and Edit SMB Shares

# Create SMB Share
$sharePath='C:\testshare'
$accessList="$env:USERDOMAIN\Domain Admins","NT AUTHORITY\Authenticated Users"
$shareName=split-path $sharePath -leaf
mkdir $sharePath
New-SmbShare -Name $shareName -Path $sharePath -FullAccess $accessList

# Check SMB Acccesses
[SMBSERVER]: PS C:\Users\kimconnect\Documents> Get-SmbShareAccess $shareName
Name          ScopeName AccountName                      AccessControlType AccessRight
----          --------- -----------                      ----------------- -----------
testshare *         KIMCONNECT\Domain Admins         Allow             Full
testshare *         NT AUTHORITY\Authenticated Users Allow             Full

# Add Share Permissions
$grantPrinciple="$env:USERDOMAIN\Domain Admins"
Grant-SmbShareAccess -Name $shareName -AccountName $grantPrinciple -AccessRight Full -Force

# Remove Share Permissions
$removePrinciple="NT AUTHORITY\Authenticated Users"
Revoke-SmbShareAccess -Name $shareName -AccountName $removePrinciple -Force

# Clone NTFS Access Control List (ACL)
# Warning: only do this to a new clone-to directory as misuse can cause permission problems
$cloneAclFrom='C:\originalshare'
$cloneAclTo=$sharePath
get-acl $cloneAclFrom|set-acl $cloneAclTo

# Check NTFS Permissions:
[SMBSERVER]: PS C:\Users\kimconnect\Documents> (get-acl c:\testshare).AccessToString
Everyone Allow  ReadAndExecute, Synchronize
CREATOR OWNER Allow  FullControl
NT AUTHORITY\SYSTEM Allow  FullControl
BUILTIN\Administrators Allow  FullControl
KIMCONNECt\TestAdmin Allow  FullControl

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

PowerShell: Allow Log On To Remote Desktop Service

# editWindowsSecurity.ps1
# Version 0.0.1
# Notes:
# - This has NOT been thoroughly tested. Microsoft Windows version variances may render this script ineffective
# - need to add a routine to translate SID into principle name as part of the matching sequence
#
# WARNING: Do Not Use Mis-use This as It Can Brick Your Windows!
# No implied or express warranties shall be assumed. Caveat Emptor!


function editWindowsSecurity{
  param(
    $principle="Remote Desktop Users",
    $privilege="SeRemoteInteractiveLogonRight",
    $operation='add' # or 'remove'
  )

  $originalSecurity='C:\originalSecurity.inf'
  $newSecurity='C:\newSecurity.inf'
  $originalDb='c:\windows\security\database\secedit.sdb'
  $securityDb='C:\originalSecurity.sdb'
  $log='C:\security.log'

  try{
    $null=get-process mmc -ea Ignore|stop-process
    cp $originalDb $securityDb -ea Stop
  }catch{
    write-warning $_
    return $false
  }
  #secedit /export /db $securityDb /mergedpolicy /cfg $originalSecurity /log $log /quiet

  $null=secedit /export /areas USER_RIGHTS /cfg $originalSecurity
  $null="[Unicode]`r`nUnicode=yes`r`n`r`n[Version]`r`nsignature=`"`$CHICAGO`$`"`r`nrevision=1`r`n`r`n[Privilege Rights]"|Out-File $newSecurity -Force -WhatIf:$false 
  $originalRights=Get-Content $originalSecurity
  $applyChanges=$false

  if($operation -eq 'add'){
    write-host "Adding $principle to $privilege..."
    foreach($line in $originalRights){ 
        if($line -like "$privilege`*"){
            write-host "Before: $line"
            $line=$line+",$principle"
            write-host "After: $line"
            $line|Out-File $newSecurity -Append -WhatIf:$false
            $applyChanges=$true
        }
    }
  }elseif($operation -eq 'remove'){
    write-host "Removing $principle from $privilege..."
    $security=$originalRights|?{$_ -match "^$privilege"}
    if($security){
      $list=[regex]::match($security,'=\s(.*)').captures.groups[1].value
      $newList=($list -split ','|?{$_ -notmatch "$principle"}) -join ','
      $line="$privilege = $newList"
      if($line -ne $security){
        write-host "Before: $security`r`nAfter:$line"
        $line|Out-File $newSecurity -Append -WhatIf:$false
        $applyChanges=$true
      }else{
        write-host "No changes."
      }
    }
  }else{
    write-warning "Please specify operation type as either ADD or REMOVE"
  }

  if($applyChanges){
    try{
      $output=SECEDIT /configure /db $securityDb /cfg $newSecurity /log $log
      write-host $output
    }catch{
      write-warning $_
      return $false
    }    
  }  
  #Remove-Item $originalSecurity -Force -WhatIf:$false
  #Remove-Item $newSecurity -Force -WhatIf:$false
}

Members of ‘Remote Desktop Users’ Not Included in the ‘Allow log on through Remote Desktop Services’ List

Error Message:
To sign in remotely, you need the right to sign in through Remote Desktop Services. By default members of the Administrators group have this right. If the group you’re in does not have the right, or if the right has been removed from the Administrators group, you need to be granted the right manually.
Cause:
Local security policy (secpol.msc) has been configured to exclude certain user groups to be absent from the 'Allow logon through Terminal Services' permissions list. Typically, that list would include Administrators, Remote Desktop Users, and Domain Admins. However, Domain Group Policies may strictly enforce certain restrictions leading to disallowing users to interactively RDP onto certain machines.
Error Message:
This setting is not compatible with computers running Windows 2000 Service Pack 1 or earlier. Apply Group Policy objects containing this setting only to computers running a later version of the operating system.
Cause:
This banner appears on certain Windows security policies that have been enforced by Active Directory Group Policy. For instance, certain high-security zones require that only Domain Administrators have access to 'Run as a Service' or 'Allow log on through Terminal Service' under the Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies/User Rights Assignment > Policy=Allow logon through Terminal Services or Policy=Run as a Service > Setting='Domain Admins',BUILTIN\Administrators

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)

 

PowerShell: Initiate Tests on Certain Ports

function initTestPort($portNumber=5985,$maxTests=3){

  function getIndexDifference {
    param(
      [String] $string1,
      [String] $string2
    )
    if ( $string1 -ceq $string2 ) {
      return -1
    }
    for ( $i = 0; $i -lt $string1.Length; $i++ ) {
      if ( $string1[$i] -cne $string2[$i] ) {
        return $i
      }
    }
    return $string1.Length
  }  

  $baseLine=(netstat -ano -p tcp|select-string "$portNumber"|out-string).trim()
  if(!$baseline){
      write-warning "$env:computername doesn't have any service listening on port $portNumber"
      exit
  }else{
      write-host "$env:computername is now listening on port $portNumber"
      do{
          $status=(netstat -ano -p tcp|select-string "$portNumber"|out-string).trim()
          if($status -ne $baseline){
            $maxTests--  
            $matchIndex=getIndexDifference $status $baseline
            $difference=$status.Substring($matchIndex).Trim()
            write-host "$maxTests remaining => $difference"
            $status=$baseline
            $null=ping 127.0.0.1 -n 1
          }
      }until(!$maxTests)
  }
}
# Test reachability from a client machine
$server='nameOrIpHere'
$port=5985
(new-object Net.Sockets.TcpClient).Connect($server, $port)

PowerShell: How To Test A Server Ephemeral Port

# Setup a listening port on server
# This session will automatically terminates after a number of test counts

function initTestEpheralPort{
  param(
    $port=59848,
    $testCount=3
  )
  $cmdlet="(new-object Net.Sockets.TcpClient).Connect('$env:computername', $port)"
  write-host "$env:computername is now listening on port $port"
  write-host "Please run this function at the client side:`r`n$cmdlet"
  $listener=[System.Net.Sockets.TcpListener]$port;
  $listener.Start();
  while($testCount) 
  {    
      $clientAccepted=$listener.AcceptTcpClient();
      if($clientAccepted){
          write-host "$((netstat -ano -p tcp|select-string "$port"|out-string))"
          $testCount--;
          Write-Host "Connection test $testCount remains!";   
      }
      $clientAccepted.Close();
      if(!$testCount){
          # Stop listening on the server
          $listener.Stop();
          write-host "Tests have completed."  
      }
  }
}

initTestEpheralPort 59848
# Test reachability from a client machine
$server='nameOrIpHere'
$port=59848
(new-object Net.Sockets.TcpClient).Connect($server, $port)

Some Useful Windows Networking Commands

# Checking WinRM connections
PS C:\Windows\system32> netstat -ano|select-string ":5985"
  TCP    0.0.0.0:5985           0.0.0.0:0              LISTENING       4
  TCP    192.11.0.7:5985        192.12.128.106:63603   SYN_RECEIVED    4  ==> indicates normal working status from within the OS
  TCP    192.11.0.7:5985        192.13.64.44:51589     SYN_RECEIVED    4

# Search MAC table on localhost
$macAddress="xx:xx:xx:xx:xx:xx"
arp -a | findstr $macAddress

# Checking network configs
PS C:\Windows\system32> Get-NetIPConfiguration
InterfaceAlias       : Ethernet 2
InterfaceIndex       : 3
InterfaceDescription : Microsoft Hyper-V Network Adapter #2
NetProfile.Name      : kimconnect.com
IPv4Address          : 192.12.134.21
IPv6DefaultGateway   :
IPv4DefaultGateway   : 192.12.134.1
DNSServer            : 192.12.130.100
                       192.12.130.101
# List adapters
PS C:\Windows\system32> Get-NetAdapter
Name                      InterfaceDescription                    ifIndex Status       MacAddress             LinkSpeed
----                      --------------------                    ------- ------       ----------             ---------
NIC2                      Broadcom NetXtreme Gigabit Ethernet #2       29 Not Present  xx-xx-xx-xx-xx-xx          0 bps
NIC4                      Broadcom NetXtreme Gigabit Ethernet #4       26 Not Present  xx-xx-xx-xx-xx-xx          0 bps
NIC Team1 - TESTLAB...     Microsoft Network Adapter Multiple...#4      25 Up           xx-xx-xx-xx-xx-xx        40 Gbps
NIC Team1                 Microsoft Network Adapter Multiplexo...      23 Up           xx-xx-xx-xx-xx-xx        40 Gbps
Ethernet 5                Intel(R) Ethernet Converged Networ...#2      21 Up           xx-xx-xx-xx-xx-xx        40 Gbps
Ethernet 4                Intel(R) Ethernet Converged Network ...      15 Up           xx-xx-xx-xx-xx-xx        40 Gbps
NIC3                      Broadcom NetXtreme Gigabit Ethernet          13 Not Present  xx-xx-xx-xx-xx-xx          0 bps
NIC1                      Broadcom NetXtreme Gigabit Ethernet #3       11 Not Present  xx-xx-xx-xx-xx-xx          0 bps
NIC Team1 - TESTLAB...     Microsoft Network Adapter Multiple...#2       8 Up           xx-xx-xx-xx-xx-xx        40 Gbps
Ethernet 2                Remote NDIS Compatible Device                 5 Not Present  xx-xx-xx-xx-xx-xx          0 bps
NIC Team1 - TESTLAB...     Microsoft Network Adapter Multiple...#3       4 Up           xx-xx-xx-xx-xx-xx        40 Gbps

# List Physical adapters
PS C:\Windows\system32> Get-NetAdapter -Physical
Name                      InterfaceDescription                    ifIndex Status       MacAddress             LinkSpeed
----                      --------------------                    ------- ------       ----------             ---------
Ethernet 5                Intel(R) Ethernet Converged Networ...#2      21 Up           xx-xx-xx-xx-xx-xx        40 Gbps
Ethernet 4                Intel(R) Ethernet Converged Network ...      15 Up           xx-xx-xx-xx-xx-xx        40 Gbps

# Get advanced properties of a NIC
$nicName="Ethernet 2"
Get-NetAdapter -Name $nicName | Get-NetAdapterAdvancedProperty

PS C:\Windows\system32> Get-NetAdapter -Name $nicName | Get-NetAdapterAdvancedProperty
Name                      DisplayName                    DisplayValue                   RegistryKeyword RegistryValue
----                      -----------                    ------------                   --------------- -------------
Ethernet 2                IPv4 Checksum Offload          Rx & Tx Enabled                *IPChecksumO... {3}
Ethernet 2                IPSec Offload                  Auth Header and ESP Enabled    *IPsecOffloadV2 {3}
Ethernet 2                Jumbo Packet                   Disabled                       *JumboPacket    {1514}
Ethernet 2                Large Send Offload Version ... Enabled                        *LsoV2IPv4      {1}
Ethernet 2                Large Send Offload Version ... Enabled                        *LsoV2IPv6      {1}
Ethernet 2                Max Number of RSS Processors   16 Processors                  *MaxRssProce... {16}
Ethernet 2                Network Direct (RDMA)          Disabled                       *NetworkDirect  {0}
Ethernet 2                Maximum Number of RSS Queues   16 Queues                      *NumRssQueues   {16}
Ethernet 2                Packet Direct                  Disabled                       *PacketDirect   {0}
Ethernet 2                Recv Segment Coalescing (IPv4) Enabled                        *RscIPv4        {1}
Ethernet 2                Recv Segment Coalescing (IPv6) Enabled                        *RscIPv6        {1}
Ethernet 2                Receive Side Scaling           Enabled                        *RSS            {1}
Ethernet 2                RSS Base Processor Number      0                              *RssBaseProc... {0}
Ethernet 2                Maximum RSS Processor Number   15                             *RssMaxProcN... {15}
Ethernet 2                RSS Profile                    NUMA Scaling Static            *RSSProfile     {4}
Ethernet 2                TCP Checksum Offload (IPv4)    Rx & Tx Enabled                *TCPChecksum... {3}
Ethernet 2                TCP Checksum Offload (IPv6)    Rx & Tx Enabled                *TCPChecksum... {3}
Ethernet 2                UDP Checksum Offload (IPv4)    Rx & Tx Enabled                *UDPChecksum... {3}
Ethernet 2                UDP Checksum Offload (IPv6)    Rx & Tx Enabled                *UDPChecksum... {3}
Ethernet 2                Forwarding Optimization        Disabled                       ForwardingOp... {0}
Ethernet 2                Hyper-V Network Adapter Name                                  HyperVNetwor... {--}
Ethernet 2                Network Address                --                             NetworkAddress  {--}
Ethernet 2                Receive Buffer Size            8MB                            ReceiveBuffe... {8192}
Ethernet 2                Send Buffer Size               1MB                            SendBufferSize  {1024}
Ethernet 2                VLAN ID                        0                              VlanID          {0}

PS C:\Windows\system32> get-netadapter -name 'NIC Team1 - VLAN101' | Get-NetAdapterAdvancedProperty
DisplayName                    DisplayValue                   RegistryKeyword RegistryValue
----                      -----------                    ------------                   --------------- -------------
NIC Team1 - HyperV...0001 Encapsulated Task Offload      Enabled                        *Encapsulate... {1}
NIC Team1 - HyperV...0001 Header Data Split              Enabled                        *HeaderDataS... {1}
NIC Team1 - HyperV...0001 IPv4 Checksum Offload          Rx & Tx Enabled                *IPChecksumO... {3}
NIC Team1 - HyperV...0001 IPsec Offload                  Auth Header & ESP Enabled      *IPsecOffloadV2 {3}
NIC Team1 - HyperV...0001 Large Send Offload Version ... Enabled                        *LsoV2IPv4      {1}
NIC Team1 - HyperV...0001 Large Send Offload Version ... Enabled                        *LsoV2IPv6      {1}
NIC Team1 - HyperV...0001 Recv Segment Coalescing (IPv4) Enabled                        *RscIPv4        {1}
NIC Team1 - HyperV...0001 Recv Segment Coalescing (IPv6) Enabled                        *RscIPv6        {1}
NIC Team1 - HyperV...0001 Receive Side Scaling           Enabled                        *RSS            {1}
NIC Team1 - HyperV...0001 TCP Checksum Offload (IPv4)    Rx & Tx Enabled                *TCPChecksum... {3}
NIC Team1 - HyperV...0001 TCP Checksum Offload (IPv6)    Rx & Tx Enabled                *TCPChecksum... {3}
NIC Team1 - HyperV...0001 UDP Checksum Offload (IPv4)    Rx & Tx Enabled                *UDPChecksum... {3}
NIC Team1 - HyperV...0001 UDP Checksum Offload (IPv6)    Rx & Tx Enabled                *UDPChecksum... {3}
NIC Team1 - HyperV...0001 Virtual Machine Queues         Enabled                        *VMQ            {1}
NIC Team1 - HyperV...0001 Virtual Machine Queues - Sh... Enabled                        *VMQLookahea... {1}
NIC Team1 - HyperV...0001 Virtual Machine Queues - VL... Enabled                        *VMQVlanFilt... {1}
NIC Team1 - HyperV...0001 MAC Address                    --                             NetworkAddress  {--}

# Check hardware information
PS C:\Windows\system32> Get-NetAdapterHardwareInfo
Name                           Segment Bus Device Function Slot NumaNode PcieLinkSpeed PcieLinkWidth Version
----                           ------- --- ------ -------- ---- -------- ------------- ------------- -------
NIC0                                 0   1      0        2             0      5.0 GT/s             8 1.1
NIC1                                 0   1      0        1             0      5.0 GT/s             8 1.1
NIC2                                 0   1      0        0             0      5.0 GT/s             8 1.1
NIC3                                 0   1      0        3             0      5.0 GT/s             8 1.1

# Set Mac address of an adapter
$macAddress2="xx-xx-xx-xx-xx-xx"
Set-NetAdapter -Name "vEthernet" -MacAddress $macAddress2

PowerShell: Compare File Counts of 2 Directories

$folder1='C:\Temp'
$folder2='C:\Temp2'
$username=$null
$password=$null

function compareFileCounts{
  param($folder1,$folder2,$mountAsUser,$mountAsPassword)
  function mountPathAsDrive($path,$driveLetter,$mountAsUser,$mountAsPassword){

    function convertPathToUnc($path,$computername=$env:computername,$credentials=$null){
      $pathIsUnc=$path -match '^\\\\'
      $pathIsReachable=if($credentials){test-path $path -credentials $credentials}else{test-path $path}
      if($pathIsUnc -and $pathIsReachable){
          return $path
      }elseif(!$pathIsUnc){
          $convertedPath=.{
                      $x=$path -replace "^([a-zA-Z])\:","\\$computername\`$1`$";
                      if($x -match '\\$'){return $x.Substring(0,$x.length-1)}else{return $x}
                      }
          $validUnc=if($convertedPath){test-path $convertedPath -ErrorAction SilentlyContinue}else{$false}
          if($validUnc){
              write-host "$path has been converted to $convertedPath, and it is reachable"
              return $convertedPath
          }else{
              write-warning "$path has been converted to $convertedPath, but it is NOT unreachable"
              return $null
          }            
      }else{
          write-warning "Path is invalid"
          return $null
      }
    }

    $pathIsUnc=$path -match '^\\\\'
    $credentials = if($mountAsUser -and $mountAsPassword){
          $password = "$mountAsPassword" | ConvertTo-SecureString -AsPlainText -Force
          New-Object System.Management.Automation.PSCredential ("$mountAsUser", $password )
      }else{
          $null
      }
    $driveLetter=if($driveLetter){
      $driveLetter
    }else{
      $unavailableDriveLetters=(Get-Volume).DriveLetter|sort
      $availableDriveLetters=.{(65..90|%{[char]$_})|?{$_ -notin $unavailableDriveLetters}}
      [char]($availableDriveLetters[0])
    }

    if($pathIsUnc){
      if($credentials){
          $null=net use "$driveLetter`:" "$path" /user:$mountAsUser "'$mountAsPassword'"
      }else{
          $null=net use "$driveLetter`:" "$path"
      }      
    }else{
        $pathAsUnc=convertPathToUnc $path
        if($credentials){
          $null=net use "$driveLetter`:" "$pathAsUnc" /user:$mountAsUser "'$mountAsPassword'"
        }else{
          $null=net use "$driveLetter`:" "$pathAsUnc"
        }
    }

    $reachable=if($credentials){test-path "$driveLetter`:\" -credentials $credentials}else{test-path "$driveLetter`:\"}
    return $(if($reachable){"$driveLetter`:\"}else{$false})
  }

  $unavailableDriveLetters=(Get-Volume).DriveLetter|sort
  $availableDriveLetters=.{(65..90|%{[char]$_})|?{$_ -notin $unavailableDriveLetters}}
  $firstDriveLetter=[char]($availableDriveLetters[0])
  $secondDriveLetter=[char]($availableDriveLetters[1])

  $path1=mountPathAsDrive $folder1 $firstDriveLetter $mountAsUser $mountAsPassword
  $path2=mountPathAsDrive $folder2 $secondDriveLetter $mountAsUser $mountAsPassword

  if($path1 -and $path2){
    $timer1=[System.Diagnostics.Stopwatch]::StartNew()
    $filesInFolder1 = Invoke-Expression -Command:"cmd.exe /C dir '$path1' /S /B /W /A:-D" -EA Ignore
    $filesCount1=$filesInFolder1.Count
    $elapsed1=[math]::round($timer1.Elapsed.TotalMinutes,2)
    $timer1.Stop()
    write-host "$folder1 (mounted as $path1) file count: $filesCount1 ($elapsed1 minutes)"
    $timer2=[System.Diagnostics.Stopwatch]::StartNew()
    $filesInFolder2 = Invoke-Expression -Command:"cmd.exe /C dir '$path2' /S /B /W /A:-D" -EA Ignore
    $filesCount2=$filesInFolder2.Count
    $elapsed2=[math]::round($timer2.Elapsed.TotalMinutes,2)
    $timer2.Stop()
    write-host "$folder2 (mounted as $path2) file count: $filesCount2 ($elapsed2 minutes)"
  }elseif(!$path1 -and !$path2){
    write-warning "Both $path1 and $path2 are NOT accessible."
  }elseif(!$path1){
    write-warning "$path1 is NOT accessible."
  }elseif(!$path2){
    write-warning "$path2 is NOT accessible."
  }
  $null=net use "$($path1[0]):" /delete
  $null=net use "$($path2[0]):" /delete
  write-host "Total duration: $($elapsed1+$elapsed2) minutes"
  return $($filesCount1 -eq $filesCount2)
}

compareFileCounts $folder1 $folder2 $username $password
# old version

$folder1='\\FILESERVER1\TEST'
$folder2='\\BACKUP1\TEST'

function compareFileCounts($folder1,$folder2){
    $filesInFolder1 = Invoke-Expression -Command:"cmd.exe /C dir '$folder1' /S /B /W /A:-D" -EA Ignore
    $fileCount1=$filesInFolder1.Count
    write-host "$folder1 file count: $fileCount1"
    $filesInFolder2 = Invoke-Expression -Command:"cmd.exe /C dir '$folder2' /S /B /W /A:-D" -EA Ignore
    $fileCount2=$filesInFolder2.Count
    write-host "$folder2 file count: $fileCount2"
    return $($fileCount1 -eq $fileCount2)    
}

compareFileCounts $folder1 $folder2

Moving a Domain Controller to a Different Geographical Location

Changing IP of a Domain Controller
        - If dcpromo has been done before the move
            - Change Nic with a new static IP
            - Run dcpromo again after the move to re-enable its role as a domain controller
        - If dcpromo has NOT been done before the move
            - Simple method:
                - Change vNic with a new static IP
                - Run dcpromo to demote
                - Run dcpromo again to promote
            - Complex method:
                - Overload vNic with a new static IP
                - Remove old IP
                - Ipconfig /flushdns && ipconfig /registerdns
                - Dcdiag /fix
        - Validate domain controller health: Dcdiag /s:DCNAME
        - Verify DNS Entries:
            - correct a-record & IP association for DOMAIN
            - reverse-lookup entries exist
            - _msdcs > dc > _sites > [Site Name] > _tcp
            - _msdcs > domains > [domain sid] > _tcp
            - _sites > [Site Name] > _tcp
            - _tcp
            - _udp
            - domaindnszones > _sites > [Site Name] > _tcp
            - forestdnszones > _sites > [Site Name] > _tcp
        - Change the DNS address in DHCP server configuration, if using DHCP for this scope
        - Update Subnets in Active Directory Sites and Services
        - Update each known client guest VMs DNS with the new IP address of DC