Archive for the ‘Windows Server’ Category

install powershell module

puppet module install puppetlabs-powershell
Under modules/module name/manifests folder create manifest file,password is encrypted with Hiera,after machine is joined to domain, it will be rebooted.
class domain_membership (
  $domain = 'ad.contoso.com',
  $username = 'administrator',
  $password = lookup('password'),
  $secure_password = false,
  $machine_ou      = 'OU=test,DC=ad,DC=contoso,DC=com',
  
){

$code = " \
\$secStr=ConvertTo-SecureString '${password}' -AsPlainText -Force; \
if (-not \$?) { \
write-error 'Error: Unable to convert password string to a secure string'; \
exit 10; \
} \
\$creds=New-Object System.Management.Automation.PSCredential( '${username}', \$secStr ); \
if (-not \$?) { \
write-error 'Error: Unable to create PSCredential object'; \
exit 20; \
} \
Add-Computer -DomainName ${domain} -OUPath $_machine_ou -Restart -Force -Cred \$creds; \
if (-not \$?) { \
write-error 'Error: Unable to join domain'; \
exit 30; \
} \
exit 0"

#
# Use the Josh Cooper PowerShell provider
#
exec { 'join_domain':

command => $code,
provider => powershell,
logoutput => true,
unless => "if ((Get-WMIObject Win32_ComputerSystem).Domain -ne '${domain}') { exit 1 }",
}

}
Advertisements

In previous post we created very first domain controller, in this one we’ll add Domain Controller to existing forest

node 'windows.example.com' {
  
 
file {['c:/NTDS']:
      ensure => directory
    }
 
dsc_windowsfeature  {'dns':
            dsc_ensure => 'Present',
            dsc_name => 'DNS',
        }
 
 
dsc_windowsfeature  { 'addsinstall':
            dsc_ensure => 'Present',
            dsc_name => 'AD-Domain-Services',
        }
 
dsc_windowsfeature  {'addstools':
            dsc_ensure => 'Present',
            dsc_name => 'RSAT-ADDS',
        }
 
 
dsc_windowsfeature  {'addnstools':
            dsc_ensure => 'Present',
            dsc_name => 'RSAT-DNS-Server',
        }
 
 
 
dsc_xwaitforaddomain {'DscForestWait':
 
   dsc_domainname => 'ad.contoso.com',
   dsc_domainusercredential=>  {
            'user'  => 'Administrator@ad.contoso.com',
            'password' => Sensitive(lookup('password'))
            },
   dsc_retrycount => 55,
   dsc_retryintervalsec => 10,
   subscribe => Dsc_windowsfeature['addsinstall'],
}
 
dsc_xaddomaincontroller {'ReplicaDC':
 
   dsc_domainname => 'ad.contoso.com',
   dsc_domainadministratorcredential => {
   'user' => 'Administrator@ad.contoso.com',
   'password' => Sensitive(lookup('password'))
   },
   dsc_safemodeadministratorpassword => {
   'user' => 'admin',
   'password' => 'Passw0rd01'
   },
   dsc_databasepath => 'C:\NTDS',
   dsc_logpath => 'C:\NTDS',
   dsc_sysvolpath => 'C:\SYSVOL',
   subscribe => Dsc_xwaitforaddomain['DscForestWait'],
    }
 
 
 
#this applies to AWS/Azure machines only
 
 
exec { 'Check if DNS is set automatically':
  command   => 'Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ResetServerAddresses',
  unless => 'if (!((netsh interface ipv4 show dns | select-string "DNS servers configured through DHCP:") -match "DNS servers configured through DHCP:")) {exit 1}',
  provider  => powershell,
  logoutput => true,
 }
 
 
reboot {'dsc_reboot':
 
 subscribe => Dsc_xaddomaincontroller['ReplicaDC'],
 message => 'DSC has requested a reboot',
 
}

 
}

I modified this script:

Add-Type -Assembly Microsoft.VisualBasic
$dc = ($env:logonserver).SubString(2)
$sitesPath = "CN=Sites,CN=Configuration," + (Get-ADDomain).DistinguishedName
$logPath = "C:\ad\logs\"
#$fileDate = get-filedate
#$fileNameBig = "import-sites_" + $env:username + "_" + $fileDate + ".log"
$fileNameBig = "CreateADSIte" + ".log"
$fileNameSmall = "ADSites" + ".JSON"
$logFileBig = $logPath + $fileNameBig
$logFileSmall = $logPath + $fileNameSmall

function init-log {
if((Test-Path $logPath) -eq $false) {
Write-Host ("Creating log folder " + $logpath + "...") -ForegroundColor "Yellow"
try {
New-Item -ItemType Directory -Path $logPath -ErrorAction Stop | Out-Null
}
catch {
Write-Warning ("Log path (" + $logPath + ") could not be created! Please change variable!")
Exit
}
Write-Host ("Log folder successfully created.") -ForegroundColor "Green"
}
if((Test-Path $logFileBig) -eq $false) {
$date = Get-Date
Write-Host ("Creating log file " + $logFileBig + "...") -ForegroundColor "Yellow"
try {
"Date: " + $date | Out-File -Append -Encoding UTF8 -FilePath $logFileBig -ErrorAction Stop
}
catch {
Write-Warning "Could not write to log file (" + $logFileBig + ") Please check!"
Exit
}
Write-Host ("Log file successfully created.") -ForegroundColor "Green"
#("UserName: " + $env:username) | Out-File -Append -Encoding UTF8 -FilePath $logFileBig
Out-File -Append -Encoding UTF8 -FilePath $logFileBig
("Log file: " + $logFileBig) | Out-File -Append -Encoding UTF8 -FilePath $logFileBig
}
}

function get-subnetAD {
param($subnet)

$ldapFilterSubnet = "(&(objectCategory=subnet)(objectClass=subnet)(name=" + $subnet + "))"
$subnetAD = Get-ADObject -LDAPFilter $ldapFilterSubnet -SearchBase $sitesPath -Server $dc -Properties siteObject, location
return $subnetAD
}

function remove-newlines {
param($string)

$string = $string = ($string.Replace("`n"," ")).Replace("`r","")
return $string
}

function get-siteAD {
param($siteName)

$ldapFilterSite = "(&(objectClass=site)(objectCategory=site)(name=" + $siteName + "))"
$siteAD = Get-ADObject -LDAPFilter $ldapFilterSite -SearchBase $sitesPath -Server $dc -Properties location
return $siteAD
}

function get-filedate {
$date = Get-Date
$year = (($date.Year).ToString()).SubString(2,2)
if($date.Month -lt 10) {
$month = "0" + $date.Month
}
else {
$month = ($date.Month).ToString()
}
if($date.Day -lt 10) {
$day = "0" + ($date.Day).ToString()
}
else {
$day = $date.Day
}

$fileDate = $year + $month + $day

return $fileDate
}

function create-site {
param($siteName,
$location)

$ldapFilterSite = "(&(objectClass=site)(objectCategory=site)(name=" + $siteName + "))"
$siteAD = Get-ADObject -LDAPFilter $ldapFilterSite -SearchBase $sitesPath -Server $dc
if($siteAD -eq $null) {
try {
$siteAD = New-ADReplicationSite -Name $siteName -Server $dc -PassThru -ErrorAction Stop
}
catch {
log-write ("ADReplicationSite " + $siteName + " could not be created. Reason: " + $_.Exception.Message) -foregroundColor "warn"
return $null
}

try {
#$siteAD = Set-ADReplicationSite -Identity $siteAD -Add @{location=$location} -Server $dc -ErrorAction Stop -PassThru
$siteAD = Set-ADReplicationSite -Identity $siteAD -Server $dc -ErrorAction Stop -PassThru
}
catch {
log-write ("ADReplicationSite " + $siteAD.Name + " could not be set. Reason: " + $_.Exception.Message) -foregroundColor "warn"
}
}
return $siteAD
}

function create-subnet {
param($subnet,
$siteAD)
#$location)

try {
$subnetAD = New-ADReplicationSubnet -Name $subnet -Site $siteAD -Location $location -Server $dc -ErrorAction Stop -PassThru
#$subnetAD = New-ADReplicationSubnet -Name $subnet -Site $siteAD -Server $dc -ErrorAction Stop -PassThru
}
catch {
log-write ("ADReplicationSubnet " + $subnet + " could not be created. Reason: " + $_.Exception.Message) -foregroundColor "warn"
return $null
}
return $subnetAD
}

function log-write {
param([String]$output,
$foregroundColor,
$backgroundColor)

#$timeStamp = get-timestamp

$output = $output

if($foregroundColor -ieq "warn") {
Write-Warning $output
}
else {
if(($backgroundColor -eq $null) -and ($foregroundColor -eq $null)) {
Write-Host $output
}
if(($backgroundColor -eq $null) -and ($foregroundColor -ne $null)) {
Write-Host $output -ForegroundColor $foregroundColor
}
if(($backgroundColor -ne $null) -and ($foregroundColor -eq $null)) {
Write-Host $output -BackgroundColor $backgroundColor
}
if(($backgroundColor -ne $null) -and ($foregroundColor -ne $null)) {
Write-Host $output -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor
}
}
try {
$output | Out-File -Append -Encoding UTF8 -FilePath $logFileBig -ErrorAction Stop
}
catch {
Write-Warning "Error writing to log file!!"
Write-Host $_.Exception.Message
}
}

function get-subnetMask {
param($subnet)

if(($subnet -eq $null) -or ($subnet -eq [String]::Empty)) {
return $null
}
$subnetMask = 0
$array = $subnet.Split(".")
foreach($octet in $array) {
if([Microsoft.VisualBasic.Information]::IsNumeric($octet)) {
$charArray = ([Convert]::ToString($octet,2)).ToCharArray()
foreach($bit in $charArray) {
$subnetMask += $bit.ToString()
}
}
else {
return $null
}
}
return $subnetMask
}

init-log

$CONFIGDATA = Get-Content -Path "C:\AD\Sites.json" | ConvertFrom-JSON

foreach($network in $CONFIGDATA)
{
$network | Add-Member NoteProperty "ADSite" $null
$subnetMask = get-subnetMask $network.Subnet
$subnet = $network.NetworkAddress + "/" + $subnetMask
$adsite=$network.SiteName

if(($network.SiteName -ne $null) -and ($network.SiteName -ne [String]::Empty)) {
$network.SiteName = remove-newlines $network.SiteName
}

$siteAD = get-siteAD $adsite

if($siteAD -eq $null) {
log-write ("Site " + $adsite + " could not be found. Creating site...") -foregroundColor "Yellow"
$siteAD = create-site $adsite
if($siteAD -eq $null) {
log-write ("Site " + $adsite + " could not be created!") -foregroundColor "warn"
#$network.SiteStatus = "Error"
export $network
continue
}
else {
log-write ("Site " + $adsite + " was successfully created") -foregroundColor "Green"
#$network.SiteStatus = "OK"
}
}

$subnetAD = get-subnetAD $subnet
if($subnetAD -eq $null) {
log-write ("Subnet could not be found in AD. Attempting to create it...") -foregroundColor "Yellow"
$subnetAD = create-subnet $subnet $siteAD
if($subnetAD -ne $null) {
log-write ("Subnet successfully created.") -foregroundColor "Green"
#$network.SubnetStatus = "OK"
}
else {
log-write ("Subnet could not be created") -foregroundColor "warn"
#$network.SubnetStatus = "Error"
#export $network
continue
}
}

}

Script above will read content of ADSites.JSON file

[
  {
    "NetworkAddress": "10.140.40.0",
    "Subnet": "255.255.252.0",
    "SiteName": "CTA001"
  },
  {
    "NetworkAddress": "10.83.0.0",
    "Subnet": "255.255.0.0",
    "SiteName": "CTA001"
  },
  {
    "NetworkAddress": "10.196.112.0",
    "Subnet": "255.255.252.0",
    "SiteName": "CTA001"
  },
  {
    "NetworkAddress": "10.196.136.0",
    "Subnet": "255.255.252.0",
    "SiteName": "CTA002"
  }
]

Script will create subnets specified in JSON file and associate it to corresponding AD site.
Puppet manifest file will create C:\AD if it doesn’t exist, will copy JSON and ps1 file from /opt/puppetfiles/  in Puppet server to C:\AD on windows node and will execute createsite.ps1 script (Script will be executed only if C:\AD\logs doesn’t exist or if log file has Subnet successfully created string.

#Create C:\AD\ directory
file {

['c:/Hentsu/']:

ensure => directory,
}

# copy JSON file with AD Site names and subnets

file { 'c:\AD\ADSites.json':
ensure => present,
content => file('/opt/puppetfiles/ADSites.json'),
}

# copy Script

file { 'c:\AD\createsite.ps1':
ensure => present,
content => file('/opt/puppetfiles/createsite.ps1'),
}

#Execute powershell script on Windows node (run it only if log files doesn't contain "Subnet successfully created"
#string
exec { 'Create sites':
command => 'C:\ad\createsite.ps1',
unless => 'if (!(Test-Path C:\AD\logs\CreateADSite.log) -or !(Select-String -Path C:\AD\logs\CreateADSite.log -Pattern "Subnet successfully created")) {exit 1}',
provider => powershell,
logoutput => true,
}

 

Install DSC  and hiera-eyaml modules (for password encryption):

puppet module install puppetlabs-dsc
puppetserver gem install hiera-eyaml
Edit /etc/puppetlabs/puppet/hiera.yaml
---
version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "Eyaml hierarchy"
    lookup_key: eyaml_lookup_key # eyaml backend
    paths:
      - "nodes/%{trusted.certname}.yaml"
      - "windowspass.eyaml"
    options:
        pkcs7_private_key: "/etc/puppetlabs/puppet/keys/private_key.pkcs7.pem"
        pkcs7_public_key: "/etc/puppetlabs/puppet/keys/public_key.pkcs7.pem"

Create keys (make sure key path reflects path from hiera.yaml file):

/opt/puppetlabs/puppet/bin/eyaml createkeys

Create password (-l is just label):

/opt/puppetlabs/puppet/bin/eyaml encrypt -l 'password' -s 'Pass' --pkcs7-public-key=/etc/puppetlabs/puppet/keys/public_key.pkcs7.pem --pkcs7-private-key=/etc/puppetlabs/puppet/keys/private_key.pkcs7.pem

Add this encrypted password to /etc/puppetlabs/puppet/data/windowspass.eyaml file:

12

/opt/puppetlabs/puppet/bin/eyaml edit windowspass.eyaml --pkcs7-public-key=/etc/puppetlabs/puppet/keys/public_key.pkcs7.pem --pkcs7-private-key=/etc/puppetlabs/puppet/keys/private_key.pkcs7.pem
cat /etc/puppetlabs/puppet/data/windowspass.eyaml
image2018-10-31_12-20-1.png

Test decryption:

/opt/puppetlabs/puppet/bin/eyaml decrypt -f windowspass.eyaml --pkcs7-public-key=/etc/puppetlabs/puppet/keys/public_key.pkcs7.pem --pkcs7-private-key=/etc/puppetlabs/puppet/keys/private_key.pkcs7.pem

Secure keys:

chown -R puppet:puppet /etc/puppetlabs/puppet/keys
chmod 400 /etc/puppetlabs/puppet/keys/private_key.pkcs7.pem
chmod 400 /etc/puppetlabs/puppet/keys/public_key.pkcs7.pem

 

For Windows currently is not possible to hide passwords when running  agent in verbose output:

puppet agent -t -v

 

Map content of windowspass.eyaml to manifest file:

'password' => Sensitive(lookup('password'))

Complete code-/etc/puppetlabs/code/environments/production/manifests/site.pp:

node 'windows.example.com' {
 
 
file {
 
['c:/NTDS']:
 
 ensure => directory
}
 
 
dsc_windowsfeature  {'dns':
            dsc_ensure => 'Present',
            dsc_name => 'DNS',
        }
 
 
dsc_windowsfeature  { 'addsinstall':
            dsc_ensure => 'Present',
            dsc_name => 'AD-Domain-Services',
        }
 
dsc_windowsfeature  {'addstools':
            dsc_ensure => 'Present',
            dsc_name => 'RSAT-ADDS',
        }
 
 
dsc_windowsfeature  {'addnstools':
            dsc_ensure => 'Present',
            dsc_name => 'RSAT-DNS-Server',
        }
 
 
 
dsc_xaddomain   { 'firstdc':
     subscribe => Dsc_windowsfeature['addsinstall'],
            dsc_domainname => 'ad.contoso.com',
     dsc_domainadministratorcredential => {
               'user' => 'pagent',
               'password' => Sensitive(lookup('password'))
     },
     dsc_safemodeadministratorpassword   => {
 'user' => 'pagent',
 'password' => 'password' => Sensitive(lookup('password'))
            },
 
            dsc_databasepath => 'c:\NTDS',
            dsc_logpath => 'c:\NTDS',
 
        }
 
 
reboot {'dsc_reboot':
 message => 'DSC has requested a reboot',
when => pending,
}

}


For debugging:

puppet master --debug --compile windows.example.com --environment=production

Creating new AD user,create New Security group and add user to it:

dsc_xADUser {'FirstUser':
dsc_ensure => 'present',
dsc_domainname => 'ad.contoso.com',
dsc_username   => 'tfl',
dsc_userprincipalname => 'tfl@ad.contoso.com',
dsc_password   => {
'user' => 'tfl@ad.contoso.com',
'password' => Sensitive(lookup('password'))
},
dsc_passwordneverexpires => true,
dsc_domainadministratorcredential => {
'user'  => 'Administrator@ad.contoso.com',
'password' => Sensitive(lookup('password'))
},
}
dsc_xgroup {'testgroup':
dsc_ensure    => 'present',
dsc_memberstoinclude => 'tfl@ad.contoso.com',
dsc_groupname   => 'test',
#dsc_credential => {
#'user' => 'Administrator@ad.contoso.com',
#'password' => 'Passw0rd01'
#},
}

In last post we installed Puppet server, in this one we’ll install Puppet agent on Windows server

Make sure Puppet server DNS name is resolvable from Windows host and vice-versa (skip this step if there is Host A DNS record for Puppet server):

C:\Windows\system32\drivers\etc\hosts

Download latest Puppet agent

image2018-10-31_12-20-1.png

Installation:

puppet-agent-5.0.0-x64.msi /qn PUPPET_MASTER_SERVER=puppetserver.example.com PUPPET_AGENT_CERTNAME=windows.example.com

If all goes smooth, certificate request file should be seen in C:\ProgramData\PuppetLabs\puppet\etc\ssl\certificate_requests

7.PNG

This certificate is waiting for signing, to do so, we need to move to Puppet server:

sudo puppet cert list
sudo puppet cert sign "windows.example.com"

On Windows server go to Puppet-Start Command Prompt with Puppet as Administrator

9.png

Test connection from Windows to Puppet server:

puppet agent --test

10.PNG

By default, Puppet agent polls Puppet server every 30 minutes.This behavior can be overridden by specifying custom polling interval by editing “C:\ProgramData\PuppetLabs\puppet\etc\puppet.conf” fileand adding line

runinterval=

One security concern is that catalog file stores credentials in plain text, to avoid this,prevent storing this file (which is in JSON format) to Puppet client

catalog_cache_terminus=""

11.png

Creating  simple manifest file

In this example we’ll make sure that IIS is installed

Install IIS module from Forge:

puppet module install puppetlabs-iis --version 4.5.0

Create manifest file and specify node and actions:

/etc/puppetlabs/code/environments/production/manifests/site.pp:

$iis_features = ['Web-WebServer','Web-Scripting-Tools','Web-Mgmt-Console']
iis_feature { $iis_features:
ensure => 'present',
include_management_tools => 'present'
}
}

Check for syntax errors:

puppet parser validate site.pp

Run powershell scripts

In order not to run script every time, when script runs if will create file with content “Done”

When Puppet tries to run this script again, it will check whether C:\log.txt or string “Done” exists in C:\log.txt, if both checks are true then script won’t be run (unless directive)

exec { 'configure_gpo':
command => 'Set-ADDefaultDomainPasswordPolicy -Identity ad.contoso.com -ComplexityEnabled $true -MinPasswordLength 7 -MinPasswordAge 1 -MaxPasswordAge 30 -LockoutDuration 00:30:00 -LockoutObservationWindow 00:30:00 -LockoutThreshold 3;write-output "Done" | out-file C:\log.txt -Append',
unless => 'if (!(Test-Path C:\log.txt) -or !(Select-String -Path C:\log.txt -Pattern "Done")) {exit 1}',
provider => powershell,
logoutput => true,
}

 

Create user in Azure AD and give him read rights over subscription and Site recovery contributor role over Azure Recovery Vault

1.PNG

Encrypt password file and install Azure module:

$username = "user@example.com"
$pwdTxt = Get-Content "C:\ExportedPassword.txt"
$securePwd = $pwdTxt | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $securePwd
Login-AzureRmAccount -Credential $cred | out-null
$vault = Get-AzureRmRecoveryServicesVault -Name "Vault"
$VaultFileLocation = Get-AzureRmRecoveryServicesVaultSettingsFile -SiteRecovery -Vault $vault
Import-AzureRmRecoveryServicesAsrVaultSettingsFile -Path $VaultFileLocation.FilePath
$Fabrics = Get-AzureRmRecoveryServicesAsrFabric
$Containers = Get-AzureRmRecoveryServicesAsrProtectionContainer -Fabric $Fabrics
$items = Get-AzureRmRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $Containers
$filename = "C:\trapper.imports";
write-host $filename;
foreach ($item in $items)
{
'"{0}" {1}' -f "server",'replication['+$item.RecoveryAzureVMName+']',""""+$item.ReplicationHealth+"""" | Add-Content -LiteralPath $filename -Encoding "Default" -Force;
}
cd "C:\Program Files\Zabbix Agent\bin\win64"
.\zabbix_sender.exe -z zabbix_server -p 10051 -c "C:\Program Files\Zabbix Agent\conf\zabbix_agentd.win.conf" -i $filename -vv
rm -Path $VaultFileLocation.FilePath
rm -Path $filename

 

Create zabbix item:

Name/key:replication[VM01]
Type:trapper

Type of infomation:Text

 

Create Trigger:
{server:replication[VM1].str(“Critical”)}=1 or {server:replication[VM01].nodata(180m)}=1

Schedule it by Task Scheduler:

Program/Script: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

Add argument: (Optional): “C:\azure_replication.ps1”

Strart in (Optional): C:\

Installing Docker on Windows

Posted: September 19, 2018 in docker, Windows Server

A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.

Go to https://store.docker.com and click on Docker CE (community Edition), main difference between Docker EE and Docker CE is that Docker CE is free 🙂

 

 

1.png

 

Click on Docker Community Edition for Windows

 

2.PNG

 

If not,create account first, the click Please Login to Download.

 

 

3.PNG

 

Download setup file and run it, in Hyper-V feature is not enabled, Setup will ask you to enable it.

 

4.PNG