Popular Posts

Tuesday, August 1, 2023

Adding domain CA trusted certificates to workgroup servers for SCCM connection

Background

In certain enterprise scenarios, it is possible to have isolated servers, a.k.a workgroup servers, that are not joined to the main Active Directory domain due reasons such as security requirements (ex: internet facing servers).

Generally, Windows Server Clients should be part of the same domain as SCCM servers to be able to retrieve packages and security updates from SCCM Distribution Points (DPs). That is because SCCM needs to trust the client before it could push/pull packages and updates.

However, there is a workround to this problem that involves installing domain certificates in workgroup servers that are not part of the domain. To add on, this could be automated using PowerShell.


Steps

1. From a domain connected client server, copy the following types of certs over to the target workgroup client server:

    a. Root

    b. CertificateAuthority

    c. TrustedPublisher

2.  Run the following PowerShell script on the workgroup server with admin privileges. It uses .NET classes x509certificate2 and x509certificate. Make sure .NET 2.0 or above is installed on the target server.

#define script log file
$logfile = 'C:\Windows\Temp\Set-Certs.log'

#function to write into the log file
function writetolog([string] $txt) {
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")

Add-content $logfile -value $Stamp':'$txt

}

#define list of certs
$certs = @(@("<corp root>.cer","Root"),@("<CA authority 1>.cer","CertificateAuthority"),@("<CA authority 2, if any>.cer","CertificateAuthority"),@("<Trusted publisher>.cer","TrustedPublisher"))

#define path to folder containing certs
$certFolder = "C:\Users\admin\Desktop\WorkgroupCerts"

#go through each cert
foreach ($certName in $certs) {
#start of the try/catch

try {

$cert = $certName[0]
Write-Host $cert

$storename = $certName[1]
write-host $storename

$certPath = "$certFolder\$cert"
Write-Host $certPath

#create a new certificate object using the x509certificate2 .NET class
$newCert = new-object system.security.cryptography.x509certificates.x509certificate2

#import the pfx file and use the x509KeyStorageFlag 'PersistKeySet' to set the certificate as persistent in our certificate store
$newCert.Import($certPath)

#get the thumbprint of the certificate going to be installed
$newCertThumbprint = $newCert.Thumbprint

#create a new object using the x509Store .NET class to manage the certificate catalog
$store = New-Object System.Security.Cryptography.X509Certificates.x509Store("\\localhost\$storename", "LocalMachine")

#open the certificate store with the 'ReadWrite' flag to be able to modify it
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags].ReadWrite)

#check if there is a certificate which match the new one's thumbprint present in the store
$certPresent = Get-ChildItem -Path CERT:\\LocalMachine -Recurse | Where-object {$_.Thumbprint -eq $newCertThumbprint}

#verify if the certificate is present. if not, install it
if(!$certPresent) {

Write-Host "Installing certificate on machine $machine"

$store.add($newCert)

}else{

Write-Host "Certificate already present on machine $machine"

}

#close the store
$store.Close()

}

catch {
throw
#update log
Write-Host "The installation has Failed on the machine $machine"

}


}





Monday, July 31, 2023

Checking EMC Networker configuration on new Windows Server builds

Background

You have been tasked to find out if EMC Networker is configured properly on your new Windows Server builds. This could be achieved by running an Ansible Playbook coupled with a PowerShell script.


Script

Playbook

#Define list of servers and their respective login details, this could be achieved differently depending on your infrastructure design
- name: capture servers list
hosts: localhost
vars:
- servers: "{{ myhost.split(',') }}"
gather_facts: false
tasks:
- import_tasks: automation-add-group.yml

- name: Check build status for windows
hosts: temp_group
gather_facts: false
tasks:
- name: Check for networker agent
win_shell: if(Get-WmiObject -Class Win32_Product | where Name -eq 'Networker') { write-host "Found" } else { write-host "Not Found" }
register: backupagent
failed_when: "'Not Found' in backupagent.stdout"
ignore_errors: true

- name: make sure networker service is running
win_service:
name: nsrexecd
state: started
register: srtbckup
ignore_errors: true

#If networker service is not running
- block:
- name: rename nsr folder
win_file:
path: C:\Program Files\EMC NetWorker\nsr\res\nsrladb
state: absent
- name: make sure network service is running
win_service:
name: nsrexecd
state: started
when: srtbckup is failed
ignore_errors: true

- pause:
seconds: 30

    #Calls the PowerShell script
- name: Check backup configuration
script: backservercheck.ps1
register: backupserver
failed_when: "'Backup client configured properly' not in backupserver.stdout"
ignore_errors: true


PowerShell

In this example, we wanted to check the backup configuration on 2 sites where each site had their own Backup servers. Hence, this script taps on the naming convention of each Windows Server to determine which Backup server it should connect to.

$hostname = $env:COMPUTERNAME

if ($hostname -like '*naming convention 1*') {

$backserverlist = @('backup server 1 - site 1','backup server 2 - site 1')

foreach ($bckupserver in $backserverlist) {

 #Define nsr command
        $command = "echo print type: nsr client; name: $hostname | nsradmin -s $bckupserver -p nsrd"

 #Run nsr command in cmd
        $output = cmd.exe /c $command

if($output -like '*scheduled backup: Enabled*') {

Write-Host "Backup client configured properly"
break

}

}

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

$backserverlist = @('backup server 1 - site 2','backup server 2 - site 2')

foreach ($bckupserver in $backserverlist) {

$command = "echo print type: nsr client; name: $hostname | nsradmin -s $bckupserver -p nsrd"

$output = cmd.exe /c $command

if($output -like '*scheduled backup: Enabled*') {

Write-Host "Backup client configured properly"
break

}

}

}

Saturday, July 1, 2023

Powershell script for checking Windows Server cluster health

Background

You have been tasked to write a script to check the health of your Windows Server clusters. Additionally, you are also required to email the cluster health report to your team.


Script

In order for the following script to work, FailoverClusters module must be imported to the sever that this script will run on. This can be achived by running the following command and it is a one-time task.

Import-Module FailoverClusters


param(

#parameter 1, cluster server list
[String]$clustersfile,
#parameter 2, email the report or not. Default is Yes.
[String]$emailtoteam="Yes"

)

#start of summary text
$summary = "############## Summary ##############`r`n"

#define log file
$logfile = "path to log file_$(get-date -f yyyyMMddhhmmss).txt"

$clusterlist = get-content $clustersfile

foreach ($cluster in $clusterlist) {

$errorflag = 0

Write-Host $cluster

$summary += $cluster

$cluster | Out-File $logfile -Append

if(Get-Cluster -Name $cluster -ErrorAction Continue) {

### cluster node
$clusternodes = Get-ClusterNode -Cluster $cluster
$clusternodes | ft | Out-File $logfile -Append

foreach ($clusternode in $clusternodes) {

if(($clusternode | select -ExpandProperty State) -ne "Up") {

$errorflag += 1 #if the status is not UP, then report error

}

}

### cluster resource
$clusterresources = Get-ClusterResource -Cluster $cluster
$clusterresources | ft | Out-File $logfile -Append

foreach ($clusterresource in $clusterresources) {

if(($clusterresource | select -ExpandProperty State) -ne "Online") {

$errorflag += 1 #if the status is not ONLINE, then report error

}

}

if($errorflag -ne 0) {

"ERROR: Check cluster`r`n" | Out-File $logfile -Append
Write-Host "Check cluster" -BackgroundColor Red -ForegroundColor White
Write-Host ""
$summary += " : Check cluster`r`n"

} else {

"OK`r`n" | Out-File $logfile -Append
Write-Host "OK" -BackgroundColor Green -ForegroundColor Black
Write-Host ""
$summary += " : OK`r`n"

}

"----------------------------------------------`r`n" | Out-File $logfile -Append

} else {
"`r`nERROR: Cannot connect to cluster, Please check manually`r`n" | Out-File $logfile -Append
"----------------------------------------------`r`n" | Out-File $logfile -Append
Write-Host "Cannot connect to cluster, Please check manually" -BackgroundColor Red -ForegroundColor White
Write-Host ""
$summary += " : Cannot connect to cluster, Please check manually`r`n"
Continue

}

}

$summary | Out-File $logfile -Append

function sendemail{

if($emailtoteam -eq "Yes") {

$smtpserver = "smtp server hostname"
$dateformat = Get-Date -Format M
$emailsubject = "Daily cluster check - $dateformat"
$to = "report recipient mailbox"

Send-MailMessage -To $to -From "sender address" -SmtpServer $smtpserver -Subject $emailsubject -Body $summary -Attachments $logfile -Cc "copied recipient mailbox if any"

}

}

sendemail