Popular Posts

Tuesday, September 1, 2020

Install Splunk Universal Forwarder on Linux using Ansible

Before automating the installation, there are some things that needs to be taken care of. 

Universal Forwarder requires you to create a splunk administrator username and password during the installation. This can either be entered at prompt during the installation or specified in the installation command line. To get around this, we will be using a user-seed.conf that contains a preconfigured username and password as follows that can be called during the installation. More on that here https://docs.splunk.com/Documentation/Splunk/8.0.5/Security/Secureyouradminaccount

[user_info]
USERNAME = admin
PASSWORD = <your password>


Playbook is as follows.

- name: Install Universal Forwarder(UF) agent
hosts: ufservers
gather_facts: no
become: yes
tasks:
- name: Get previous versions of UF if installed
shell: rpm -qa | grep splunk
register: oldUFnamerpm
ignore_errors: yes
- debug:
var: oldUFnamerpm
- name: Remove previous version of UF
block:
- name: Remove old splunk from boot script
shell: ./splunk disable boot-start
args:
chdir: /opt/splunkforwarder/bin
- name: Stop old splunk
shell: ./splunk stop
args:
chdir: /opt/splunkforwarder/bin
- name: Uninstall previous version of UF
shell: rpm -e {{ oldUFnamerpm.stdout }}
when: oldUFnamerpm.stdout != ""
ignore_errors: yes
- name: Get old splunk process
shell: netstat -tulpn | grep -i splunkd | awk '{print $7}' | awk -F/ '{print $1}' | head -1
register: oldUFproc
- name: Kill old splunk process
shell: kill -9 {{ oldUFproc.stdout }}
when: oldUFproc.stdout != ""
- name: Remove old splunk dir
file:
path: /opt/splunkforwarder
state: absent
- name: Copy tgz from control server to remote node
copy:
src: /home/yinidu/Linux_UF/splunkforwarder-8.0.0-1357bef0a7f6-Linux-x86_64.tgz
dest: /home/yinidu
- name: Untar tgz
shell: tar xvfz splunkforwarder-8.0.0-1357bef0a7f6-Linux-x86_64.tgz
args:
chdir: /home/yinidu
- name: Move untar file to /opt
shell: mv /home/yinidu/splunkforwarder /opt/
- name: Copy user seed from control server to remote node
copy:
src: /home/yinidu/Linux_UF/user-seed.conf
dest: /opt/splunkforwarder/etc/system/local/user-seed.conf
- name: Install splunk
shell: ./splunk start --accept-license --answer-yes --no-prompt
args:
chdir: /opt/splunkforwarder/bin
- pause:
seconds: 10
- name: Stop splunk
shell: ./splunk stop
args:
chdir: /opt/splunkforwarder/bin
- name: Add splunk user
user:
name: splunk
state: present
- name: Enable boot-start
shell: ./splunk enable boot-start -user splunk
args:
chdir: /opt/splunkforwarder/bin
- name: Change folder permission
shell: chown -R splunk:splunk /opt/splunkforwarder
- name: Start splunk
service:
name: splunk
state: started
- name: Copy org_all_forwarder_outputs which contains heavy forwarder configuration
copy:
src: /home/yinidu/Linux_UF/org_all_forwarder_outputs
dest: /opt/splunkforwarder/etc/apps/
- name: Copy Splunk_TA_nix which contains input parameters
copy:
src: /home/yinidu/Linux_UF/Splunk_TA_nix
dest: /opt/splunkforwarder/etc/apps/
- name: Change folder permission
shell: chown -R splunk:splunk /opt/splunkforwarder
- name: Restart splunk
service:
name: splunk
state: restarted
- name: Set permission on /var/log
shell: setfacl --recursive -m u:splunk:r-x,d:u:splunk:r-x /var/log
- name: Check netstat to make sure UF is connected to the heavy forwarder
shell: netstat -an | grep 9997
register: netstatop
- debug:
var: netstatop.stdout

Monday, August 31, 2020

Extending a disk on a window system using PowerShell and PowerCLI

Identify the correct disk to extend on OS

param(

[string]$drivename #ex: C or D
$percentage = 1.1

)

try{

$moddrivename = $drivename + ":"

$extendnumber = [math]::Round(((Get-WmiObject -Class Win32_LogicalDisk | where DeviceID -like $moddrivename | select -ExpandProperty Size) /1TB)*$percentage)

if ($extendnumber -ge 2) {

return "2TBDisk"

}

$searchstring = '\\' +$env:computername+ '\root\cimv2:Win32_LogicalDisk.DeviceID="' +$drivename+ ':"'

$disknumberlong = Get-WmiObject -Class Win32_LogicalDiskToPartition | where Dependent -Like $searchstring | select -ExpandProperty Antecedent

$disknumberlong -match 'Disk #(\d+)' | out-null

$disknumber = $matches[0].split('#')[1]

return $disknumber

} catch {

throw

}




Extending VM disk

param(

[String]$serverfqdn,
[String]$disknumber, #passed from the previous script
[double]$percentage=1.1 #percentage at which the disk should be extended by

)

Get-Module -Name VMware* -ListAvailable | Import-Module #call PowerCLI module


$vcusername = ''
$vcpassword = ''

$hostname = $serverfqdn.split(".")[0]

if ($hostname -like 'some naming convention') {

$vcservers = @("vc1","vc2")

foreach ($vc in $vcservers) {

Connect-VIServer -Server $vc -User $vcusername -Password $vcpassword

if ($vm = Get-VM $hostname) {

$correctvc = $vc
break

}

else {

Disconnect-VIServer -Server $vc -Confirm:$false
continue

}

}

} elseif ($hostname -like 'some naming convention 2') {

$vcservers = @("vc3","vc4")

foreach ($vc in $vcservers) {

Connect-VIServer -Server $vc -User $vcusername -Password $vcpassword

if ($vm = Get-VM $hostname) {

$correctvc = $vc
break

}

else {

Disconnect-VIServer -Server $vc -Confirm:$false
continue

}

}

}

#we assume most disks are using the first controller
$SCSI = '0:'+$disknumber

#heres the tricky part, pass each disk on the VM to get-scsicontroller which returns it's respective busnumber and unit number. Then get the disk name by filtering the result using the $SCSI variable.
$diskname = Get-VM $hostname | Get-HardDisk | Select @{N='VM';E={$_.Parent.Name}},Name,@{N='Node';E={'{0}:{1}' -f ((Get-ScsiController -HardDisk $_).ExtensionData.BusNumber),$_.ExtensionData.UnitNumber}} | where Node-like $SCSI | select Name -ExpandProperty Name

$disksize = Get-HardDisk -VM $hostname | where {$_.Name -eq $diskname} | select -ExpandProperty CapacityGB

$newdisksize = $disksize*$percentage

Write-Host $newdisksize

Get-HardDisk -VM $hostname | where {$_.Name -eq $diskname} | Set-HardDisk -CapacityGB $newdisksize -confirm:$false

Disconnect-VIServer -Server $correctvc -Confirm:$false



Extending disk on OS

param(

[string]$drivename,
[double]$percentage=0.1

)


try{

"RESCAN" | diskpart

$moddrivename = $drivename + ":"

$extendnumber = [math]::Round(((Get-WmiObject -Class Win32_LogicalDisk | where DeviceID -like $moddrivename | select -ExpandProperty Size) /1MB)*$percentage)
write-host $extendnumber

$searchstring = '\\' +$env:computername+ '\root\cimv2:Win32_LogicalDisk.DeviceID="' +$drivename+ ':"'

$disknumberlong = Get-WmiObject -Class Win32_LogicalDiskToPartition | where Dependent -Like $searchstring | select -ExpandProperty Antecedent

$disknumberlong -match 'Disk #(\d)'

$disknumber = $matches[0].split('#')[1]

$string1 = "select disk " + $disknumber
$string2 = "select volume " + $drivename
$string3 = "extend size=" + $extendnumber

$commands = @(
$string1,
$string2,
$string3
)

$commands | diskpart

Write-Host "Disk extension on OS layer completed"
exit 0

} catch {

Write-Host "Disk extension on OS layer failed"
exit -1

}

Thursday, August 20, 2020

Common SSL/TLS vulnerability fixes

SSL/TLS Diffie-Hellman Modulus <= 1024 Bits (Logjam)

Configure the following registry and restart the server


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman]

"ServerMinKeyBitLength"=dword:00000800




Transport Layer Security (TLS) Protocol CRIME Vulnerability - Splunkd port 8089


Change allowSslCompression = true to false and restart splunkforwarder service


C:\Program Files\SplunkUniversalForwarder\etc\system\default>more server.conf | findstr allowSslCompression

allowSslCompression = false




SSL/TLS Diffie-Hellman Modulus <= 1024 Bits (Logjam)


Add the following line in sshd_config and restart sshd service


# Ciphers and keying

Ciphers chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com

 

Thursday, August 13, 2020

Shutdown and Startup VMs using PowerCLI

Shutdown

param (
[Parameter(Mandatory=$true)]
$serverslistfile
)
function writetolog([string] $txt) {
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
Add-content $logfile -value $Stamp':'$txt
}
$vCenter = 'vcentername'
$logfile = 'C:\Windows\Temp\DR_ShutdownVMs.log'
$serverslist = Get-Content $serverslistfile
Write-host "############################## ABC company DR activity - Shutdown VMs ##############################"
writetolog("############################## ABC company DR activity - Shutdown VMs ##############################")
Write-Host "vCenter server selected : "$vCenter
writetolog("vCenter server selected : " + $vCenter)
Write-Host "Servers list selected : "
writetolog("Servers list selected : ")
$serverslist | ForEach-Object { Write-Host $_ ; writetolog($_) }
$Confirm = Read-Host "Please type 'ok' to confirm selection is correct"
if($Confirm -eq 'ok') {
writetolog("Proceed: OK by $env:UserName")
try{
Connect-VIServer $vCenter
Write-Host "Successfully connected to $vCenter vCenter"
writetolog("Successfully connected to $vCenter vCenter")
} catch {
Write-Host "Cannot connect to $vCenter vCenter, Exiting Program"
writetolog("Cannot connect to $vCenter vCenter, Exiting Program")
exit -1
}
$serverslist | foreach-object {
if((Get-VM $_ | select -ExpandProperty PowerState) -eq "PoweredOn") {
try {
shutdown-vmguest $_ -Confirm:$false | Out-Null
Write-Host $_ "Shutdown-ed"
writetolog($_ + " Shutdown-ed")
} catch{
Write-host $_ "Error"
writetolog($_ + " Error Shutting down")
}
} else {
Write-host $_ "Already Powered Down"
writetolog($_ + " Already Powered Down")
}
}
Disconnect-VIServer $vCenter -Confirm:$false
Write-Host "Successfully disconnected from $vCenter vCenter"
writetolog("Successfully disconnected from $vCenter vCenter")
} else {
exit
}




Startup


param (
[Parameter(Mandatory=$true)]
$serverslistfile
)
function writetolog([string] $txt) {
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
Add-content $logfile -value $Stamp':'$txt
}
$vCenter = 'vcentername'
$logfile = 'C:\Windows\Temp\DR_PowerOnVMs.log'
$serverslist = Get-Content $serverslistfile
Write-host "############################## ABC company R activity - Power On VMs ##############################"
writetolog("############################## ABC company DR activity - Power On VMs ##############################")
Write-Host "vCenter server selected : "$vCenter
writetolog("vCenter server selected : " + $vCenter)
Write-Host "Servers list selected : "
writetolog("Servers list selected : ")
$serverslist | ForEach-Object { Write-Host $_ ; writetolog($_) }
$Confirm = Read-Host "Please type 'ok' to confirm selection is correct"
if($Confirm -eq 'ok') {
writetolog("Proceed: OK by $env:UserName")
try{
Connect-VIServer $vCenter
Write-Host "Successfully connected to $vCenter vCenter"
writetolog("Successfully connected to $vCenter vCenter")
} catch {
Write-Host "Cannot connect to $vCenter vCenter, Exiting Program"
writetolog("Cannot connect to $vCenter vCenter, Exiting Program")
exit -1
}
$serverslist | foreach-object {
if((Get-VM $_ | select -ExpandProperty PowerState) -eq "PoweredOff") {
try {
Start-VM $_ -Confirm:$false | out-null
Write-Host $_ "Powered On"
writetolog($_ + " Powered On")
} catch{
Write-host $_ "Error"
writetolog($_ + " Error Powering On")
}
} else {
Write-host $_ "Already Powered On"
writetolog($_ + " Already Powered On")
}
}
Disconnect-VIServer $vCenter -Confirm:$false
Write-Host "Successfully disconnected from $vCenter vCenter"
writetolog("Successfully disconnected from $vCenter vCenter")
} else {
exit
}

Get and Set DNS search order using PowerShell

Get DNS

Scenario: I was asked to generate a list of servers that were still using our old DNS servers. This script was included in an SCCM DCM baseline to generate the report.

try{
$isComplaint = $true
$Interface = Get-WMIObject Win32_NetworkAdapterConfiguration | where{$_.IPEnabled -eq “True” -and $_.IPAddress -like "10.*"} -ErrorAction Stop
Foreach($NIC in $Interface) {
$IPs = $NIC.DNSServerSearchOrder
Foreach($IP in $IPs) {
if(($IP -eq 'your.old.DNS.ip') -or ($IP -eq 'your.old.DNS.ip2')) {
$isComplaint = $false
return "Non-Compliant"
}
}
}
if ($isComplaint -eq $true) {
return "Compliant"
}
}
catch{
return "Error"
}




Set DNS

Scenario: Configure new DNS server in DNS search order for those servers still using old DNS server. For this, we created a SCCM task sequence consisting of following script and deployed to a collection of computers. The DNS server list was passed through a TS variable "DNSservers". If you are only intrested about the PowerShell portion, then pass the DNS server list in the following format $DNSServers = “198.168.1.10",”198.168.1.2". The reason why we didnt directly ran the script on all servers was because there were a mixture of domain and workgroup servers that needed this change. We were able to run the script all servers using SCCM without bothering about the connection/authentication challenges.

$logfile = 'C:\Windows\Temp\SetDNS.log'
function writetolog([string] $txt) {
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
Add-content $logfile -value $Stamp':'$txt
}
try{
$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$DNSServers = $tsenv.Value("DNSservers")
write-host "Retrieved DNS servers list successfully"
writetolog("Retrieved DNS servers list successfully : " + $DNSServers)
$DNSServers = $DNSServers -split ','
}
catch{
write-host "Cannot retrieve DNS servers list"
writetolog("Retrieved DNS servers list successfully")
exit -1
}
#$DNSServers = “198.168.1.10",”198.168.1.2"
try{
$Interface = Get-WMIObject Win32_NetworkAdapterConfiguration | where{$_.IPEnabled -eq “True” -and $_.IPAddress -like "10.*"} -ErrorAction Stop
write-host "Connected to WMI succesfully and interfaces retrieved"
writetolog("Connected to WMI succesfully and interfaces retrieved")
Foreach($NIC in $Interface) {
try{
$NIC.SetDNSServerSearchOrder($DNSServers)
write-host "DNS servers configured successfully"
writetolog("DNS servers configured successfully")
exit 0
}
catch{
write-host "Cannot set DNS servers"
writetolog("Cannot set DNS servers")
exit -1
}
}
}
catch{
write-host "Cannot connect to WMI"
writetolog("Cannot connect to WMI")
return -1
}


 







Export list of all hosts in Ansible Tower Inventory using PowerShell

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$serversarray = @()
$cred = Get-Credential

$capture = Invoke-RestMethod -Uri "https://towerhostURL/api/v2/hosts/" -Method Get -Credential $cred
$count = $capture.results.Count
for ($i = 0; $i -lt $count; $i++) {
$servername = $capture.results[$i].name
$group = $capture.results[$i].summary_fields.groups.results[0].name
$server = New-Object System.Object
$server | Add-Member -MemberType NoteProperty -Name ServerName -Value $servername
$server | Add-Member -MemberType NoteProperty -Name Group -Value $group
$serversarray += $server
}
while ($capture.next -ne $null) {
Write-Host $capture.next
$link = $capture.next
$capture = Invoke-RestMethod -Uri "https://towerhostURL$link" -Method Get -Credential $cred
$count = $capture.results.Count
for ($i = 0; $i -lt $count; $i++) {
$servername = $capture.results[$i].name
$group = $capture.results[$i].summary_fields.groups.results[0].name
$server = New-Object System.Object
$server | Add-Member -MemberType NoteProperty -Name ServerName -Value $servername
$server | Add-Member -MemberType NoteProperty -Name Group -Value $group
$serversarray += $server
}
}
$serversarray | Export-Csv -NoTypeInformation .\Ansiblehostslist.csv
$serversarray.Clear()

Get network interfaces of all VMs in an Azure subscription using PowerShell

$subs = Get-AzureRmSubscription

$array = @()
foreach ($sub in $subs)
{
Set-AzureRmContext -SubscriptionId $sub.Id | Out-Null
$rmVMs = Get-AzureRmVM
Write-Output "Subscription $($sub.Id) VMs: $($rmVMs.Count)"
foreach ($vm in $rmVMs) {
Write-Host $vm.Name
$nicCount = $vm.NetworkProfile.NetworkInterfaces.count
write-host $nicCount
for ($i = 0; $i -lt $nicCount; $i++) {
$networkInterfaceID = $vm.NetworkProfile.NetworkInterfaces[$i].Id
$networkInterfaceResourceGroupName = $networkInterfaceID.Split('/')[4]
$networkInterfaceName = $networkInterfaceID.Split('/')[-1]
Write-Host $networkInterfaceName
$networkInterface = Get-AzureRmNetworkInterface -ResourceGroupName $networkInterfaceResourceGroupName -Name $networkInterfaceName
$PrivateIP = $networkInterface | Get-AzureRmNetworkInterfaceIpConfig | Select -ExpandProperty PrivateIPAddress | Out-String
Write-Host $PrivateIP
$server = New-Object System.Object
$server | Add-Member -MemberType NoteProperty -Name VM -Value $vm.Name
$server | Add-Member -MemberType NoteProperty -Name NIC -Value $networkInterfaceName
$server | Add-Member -MemberType NoteProperty -Name PrivateIP -Value $PrivateIP
if($networkInterface.IpConfigurations.PublicIpAddress -ne $null) {
$publicIPinterface = $networkInterface.IpConfigurations.PublicIpAddress[0].Id
$publicIPinterfaceName = $publicIPinterface.Split('/')[-1]
$PublicIP = Get-AzureRmPublicIpAddress -ResourceGroupName $networkInterfaceResourceGroupName -Name $publicIPinterfaceName | select -ExpandProperty IpAddress | Out-String
}
$server | Add-Member -MemberType NoteProperty -Name PublicIP -Value $PublicIP
$array += $server
}
}
}
$array | Export-Csv -NoTypeInformation .\azurermVMip.csv
$array.Clear()

Check missing updates on a SCCM client using PowerShell

write-host "Checking compliance on" $env:computername

#identify the assignments on this host
$UpdateAssignment = Get-WmiObject -Query "Select * from CCM_AssignmentCompliance" -Namespace root\ccm\SoftwareUpdates\DeploymentAgent -ErrorAction SilentlyContinue

#for each assignment, show the assignment ID
if($UpdateAssignment){
$UpdateAssignment | ForEach-Object{
Write-Host "Deployments"
Write-Host $_.AssignmentId
}
#within each assignment, get updates that are yet to be installed
$TargetedUpdates = Get-WmiObject -Query "Select * from CCM_TargetedUpdateEX1 where UpdateState = 0" -Namespace root\ccm\SoftwareUpdates\DeploymentAgent -ErrorAction Stop
if($TargetedUpdates){
$iMissing=0
$TargetedUpdates | ForEach-Object {
$iMissing++
}
write-host -BackgroundColor Red "Number of Missing Updates: $iMissing"
write-host $iMissing
}
else {
Write-Host -BackgroundColor Green -ForegroundColor Black "No Missing Software Updates Found"
}
}
else{

write-host -BackgroundColor Red "No Deployments Assigned"
}



write-host "Checking full compliance on" $env:computername

#this method will identify missing updates on this host regardless of the assignments
$allupdates = Get-WmiObject -Query "select * from CCM_UpdateStatus where Status='missing'" -Namespace root\ccm\SoftwareUpdates\UpdatesStore

$allupdates | ForEach-object{
write-host $_.Article
write-host $_.Title
write-host $_.Status
write-host ""
}

Wednesday, August 12, 2020

Manage SCCM using PowerShell

Remove member from SCCM collection

param(

[Parameter(Mandatory=$true)]

[String]$serverslistfile,

[Parameter(Mandatory=$true)]

[String]$collectionName,

[String]$smsServer = 'SCCMDPservername',

[String]$smsNamespace = 'root\sms\site_NAME'

)

$serverslist = Get-Content $serverslistfile

function remove-fromCollection {

$collection = Get-WmiObject -ComputerName $smsServer -Query "select * from SMS_Collection where Name LIKE '$collectionName'" -Namespace $smsNamespace #-Credential $Cred

$collection.get()

$serverslist.Split(",") | foreach {

$serverName = $_.split(".")[0]

Write-Host $serverName

$rule = $collection.CollectionRules | where {$_.RuleName -eq "$serverName"}

$collection.DeleteMemberShipRule($rule)

}

}

remove-fromCollection




Delete computer from SCCM

param(
[String]$serverslistfile,
[String]$smsServer = ‘SCCMDPservername’,
[String]$smsNamespace = 'root\sms\site_NAME'
)
$serverslist = Get-Content $serverslistfile

function delete-device {
$serverslist | foreach {

$serverName = $_.split(".")[0]

$resource = Get-WmiObject -ComputerName $smsServer -Query "select * from SMS_R_SYSTEM where Name LIKE '$serverName'" -Namespace $smsNamespace

write-host "Deleting $serverName"

$resource.delete()
}
}

delete-device


Monday, August 10, 2020

Change user password, enable account using Ansible

- name: Change password
hosts: all
gather_facts: no
remote_user: root
tasks:
- user:
name: username1
password: "{{ 'password' | password_hash('sha512') }}"
- user:
name: username2
password: "{{ 'password' | password_hash('sha512') }}"
- name: Enable account and set expiry
hosts: all
gather_facts: no
remote_user: root
tasks:
- name: change expiry date
user:
name: user1
expires: time in epochtime
- name: change expiry date 1
user:
name: user2
expires: time in epochtime

Friday, August 7, 2020

Collect hardware metrics from physical Windows Servers

Background

It is often needed to monitor your server infrastructure in terms of performance metrics. Virtual servers could be monitored through hypervisor management software such as VMware vSphere and Microsoft Hyper-V. However, monitoring physical servers for hardware metrics in the absense of a monitoring solution could be a challenge.


Script/Commands

The following commands can be incorporated in your script to retrieve hardware metrics

$cpuUsage = [math]::Round((Get-Counter -ComputerName $server '\Processor(_Total)\% Processor Time' | 
select CounterSamples -ExpandProperty CounterSamples | select CookedValue -ExpandProperty CookedValue),0)

$os = Get-WmiObject -ComputerName $server win32_OperatingSystem

$memUsage = [math]::Round(100-(($os.FreePhysicalMemory/$os.TotalVisibleMemorySize)*100),0)

$freemem = [math]::Round($os.FreePhysicalMemory/1048576,0)

$memsize = [math]::Round($os.TotalVisibleMemorySize/1048576,0)

#Drive type 3 refers to local disk
Get-WmiObject -ComputerName $server win32_logicaldisk -Filter DriveType='3' | foreach {

$diskname = $_.DeviceID
$size = [math]::Round($_.Size/1GB,0)
$freesize = [math]::Round($_.FreeSpace/1GB,0)
$diskfree = [math]::Round(($freesize / $size)*100,0) #As a percentage

}

Monday, July 20, 2020

RDP not working after remediating sweet32

After doing some research on the web and comparing the Administrative ToolsàRemote Desktop ServicesàRemote Desktop Session Host ConfigurationàConnectionsàRDP-TcpàProperties between the working servers and problematic servers, I have done the following changes to make RDP work:

 

  1. Change Encryption level from FIPS Complaint to High

 

  1. It seems any of the following changes will fix the issue together with #1 above

 

    1. Change the following registry value to 1 from 2 that changes the setting from SSL(TLS1.0) to Negotiate (because the Security Layer option was greyed out)

 

HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\SecurityLayer

 

    1. Alternatively, I could also make RDP work by enabling the following local policy

 

Computer configuration\Administrative Templates\Windows Components\Remote Desktop Services\Remote Desktop Session\Connections\Allow users to connect remotely using Remote Desktop Services

 

Clients cannot connect to SCCM DP for content Error sending DAV request. HTTP code 401, status 'Unauthorized'

Make sure NTLM is allowed on the clients if DP IIS is configured for windows authentication

Thursday, July 16, 2020

Install .NET 3.5 feature using PowerShell

If you require .NET 3.5 to be installed on a windows system, you can do so using the Server Manager utility. But in some cases, you might end up with an error due to unknown reasons. If you lookup this issue on the web, there are suggestions to check windows firewall, loop back address etc. If you do not want to bother about those trivial things, here are some steps that you can follow as a workaround:

1. Mount windows .iso on your CD drvie
2. Enter the following command on PowerShell
    Install-WindowsFeature -Name NET-Framework-Core -source <cd drive:>

Friday, March 13, 2020

Generate report to identify the occurence of certain event ID in Windows Servers

Background

IT audit findings in my organisation discovered the occurence of event ID 4625 in some of our Windows Servers. Event ID 4625 is a security event that is generated when an account fails to log on. It is important to identify what, when and how this event was generated as it may refer to a potential case of unauthorised access. Additionally, investigating such events helps in identifying local accounts of the Windows Server system that need a change of password.


Script

The following script is scheduled to run daily, hence, only events of the past 24 are considered. The functionality of the script can be listed as follows:

  1. Get the list of servers
  2. Connect to each server and collect event IDs according to set filters (this script could be used to capture any event ID of your choice)
  3. Convert and parse event as XML to gather more details such as username, date and time, ip address etc.
  4. Export the findings to an Excel spreadsheet and create pivot table to summarise the findings

Make sure to run the following command to import the excel module before running this script (one time task)

Import-Module ImportExcel

If the server is not connected to the internet as in most scenarios, you may download the package from https://github.com/dfinke/ImportExcel and place it in the C:\Windows\System32\WindowsPowerShell\v1.0\Modules and then run Import-Module ImportExcel

The beauty of this module is that you can create and edit excel files without having to install MS Excel.

 

$servers = get-content "path to server list"

#oldest event we are looking for should be 1 day older
$oldest = (get-date).adddays(-1)

$newest = get-date

$outfile = "path to excel file_$(get-date -f yyyy-MM-dd).xlsx"

#initiate empty data collection to store the events
$datacol = @()

#initiate empty data collection to store failed hosts
$errordatacol = @()

#function to create PS object that represents one event
function createerrorPSObj($hostname,$error) {
$errordata = New-Object -TypeName PSObject

$errordata | Add-Member -MemberType NoteProperty -Name Hostname -value $hostname

$errordata | Add-Member -MemberType NoteProperty -Name Error -value $error

return $errordata
}

foreach ($server in $servers) {

Write-Host $server

#this is test to see if the server is reachable
if(Get-WmiObject -ComputerName $server win32_computersystem -ErrorAction Continue) {

} else {
#if the test fails, insert in error data collection
$errordatacol += createerrorPSObj $server $Error[0]
Continue

}
#get events per server
$events = Get-WinEvent -ComputerName $server -FilterHashtable @{LogName='Security'; ID='4625'; Starttime=$oldest; endtime=$newest} -ErrorAction Continue

if($events) {

foreach($event in $events) {

$data = New-Object -TypeName PSObject

#capture each event in xml format
$eventXML = [xml]$event.ToXml()

$data | Add-Member -MemberType NoteProperty -Name Hostname -value $server

$EventID = $event.id
$data | Add-Member -MemberType NoteProperty -Name EventID -value $EventID

$ProcessName = $eventXML.Event.EventData.Data[18].'#text'
$data | Add-Member -MemberType NoteProperty -Name ProcessName -value $ProcessName

$Workstation = $eventXML.Event.EventData.Data[13].'#text'
$data | Add-Member -MemberType NoteProperty -Name WorkstationName -value $Workstation

$EventTime = $event.timecreated
$data | Add-Member -MemberType NoteProperty -Name EventTime -value $EventTime
$LogonType = $eventXML.Event.EventData.Data[10].'#text'
$data | Add-Member -MemberType NoteProperty -Name LogonType -value $LogonType

$IpAddress = $eventXML.Event.EventData.Data[19].'#text'
$data | Add-Member -MemberType NoteProperty -Name IpAddress -value $IpAddress
$UserName = $eventXML.Event.EventData.Data[5].'#text'
$data | Add-Member -MemberType NoteProperty -Name UserName -value $UserName
#add current data object to data collection
$datacol += $data

}

}

}

#excel parameters
$ExcelParams = @{

Path = $outfile
IncludePivotTable = $true
PivotRows = 'Username','Hostname'
PivotTableName = 'pivot'
PivotData = @{'Username' = 'count'} #Pivot table for the count of username per host
Activate = $true

}

#export data collection into Excel using parameters defined above
$excel = $datacol | Export-Excel @ExcelParams

#export error data collection into Excel on a seperate worksheet
$errordatacolGDC | Export-Excel $outfile -WorksheetName 'Script Errors' -AutoSize -AutoFilter -FreezeTopRow -TitleBold


The pivot table should appear as follows: