Docker Containers for Infrastructure

It’s nice for labs to be able to spin things up fast. What better way to do it than with Docker containers? I’ll add more here as I use them.


docker run -d -p 389:389 \
  -e SLAPD_PASSWORD=iw2slep! \
  -e \
  --name openldap dinkel/openldap

docker run -d -p 80:80 \
  --link openldap:openldap \
  --name ldapadmin dinkel/phpldapadmin


docker run --name bind -d --restart=always \
  --publish 53:53/tcp \
  --publish 53:53/udp \
  --publish 10000:10000/tcp \
  --volume /srv/docker/bind:/data \


docker run -d -p 80  quantumobject/docker-cacti

Docker Install on Ubuntu

A simple script for installing Docker on an Ubuntu host.

apt-get update
apt-get install apt-transport-https ca-certificates curl software-properties-common curl -y
curl -fsSL | sudo apt-key add -
add-apt-repository "deb [arch=amd64] $(lsb_release -cs) stable"
sudo apt-get update
apt-get install -y docker-ce

PowerShell Powered DDNS with AWS

I wanted to write a script to update DNS records in AWS to make my own Dynamic DNS solution. I got the idea from some scripts I’d seen online, but really didn’t want to deal with all the Python.
Instead, I found that you can get AWS PowerShell cmdlets to do the same thing. Yay!

# Install AWS PowerShell tools 
# Install-Module $module -Scope CurrentUser 
# Scope required if installing without administrative rights

Import-Module AWSPowerShell

# AWS Information
$AccessID="**Access ID Here**"
$SecureID="**Secure ID Here**"
$ZoneID="**Zone ID Here**"
$Recordset="**FQDN to be updated Here**"

# Determine public IP address
$IP=(Resolve-DnsName -Name -Server

# Get the current IP address value of the record
$RecordData=(Test-R53DNSAnswer -AccessKey $AccessID -SecretKey $SecureID -HostedZoneId $ZoneID -RecordName $Recordset -RecordType $type).RecordData

If ($IP -eq $RecordData) # Check to see if the IP value of the record is correct or needs to be updated
    "Record data correct, no action required"
    # Set parameters to delete the existng record
    $Delete = New-Object Amazon.Route53.Model.Change
    $Delete.Action = "DELETE"
    $Delete.ResourceRecordSet = New-Object Amazon.Route53.Model.ResourceRecordSet
    $Delete.ResourceRecordSet.Name = $Recordset
    $Delete.ResourceRecordSet.Type = $Type
    $Delete.ResourceRecordSet.TTL = $TTL

    # Set parameters to create a new record with the correct IP address
    $Create = New-Object Amazon.Route53.Model.Change
    $Create.Action = "CREATE"
    $Create.ResourceRecordSet = New-Object Amazon.Route53.Model.ResourceRecordSet
    $Create.ResourceRecordSet.Name = $IP
    $Create.ResourceRecordSet.Type = $Type
    $Create.ResourceRecordSet.TTL = $TTL

    # Execute the deletion and creation of the record
    Edit-R53ResourceRecordSet -AccessKey $AccessID -SecretKey $SecureID -HostedZoneId $ZoneID -ChangeBatch_Change $Delete,$Create

VMware Photon on VMware Workstation

VMware Photon is a lightweight OS used for cloud-native workloads. The Photon OS is also designed to host Docker for containerized workloads. Able to run within a vSphere environment and can also be easily run within within VMware Workstation for testing.

1. Download the OVA image from the Photon Github site
2. In VMware Workstation click File – Open and navigate to the OVA image
3. Name the VM and specify the storage and click Import
4. Accept the EULA
5. Upon completion of the import process edit VM settings
6. Select the options tab and click General, set Guest Operating System to Linux and Version to VMware Photon 64-Bit
7. Power on VM
8. Log in at the VM console and you will be required to update the root password – (Username – root / Password – changeme)
9. Open the docker.service file (/etc/systemd/system/
10. Update “ExecStart=/bin/docker” to “ExecStart=/bin/docker -H tcp:// -H unix:///var/run/docker.sock -s overlay”
11. Enable and start Docker by running systemctl enable docker && systemctl start docker
12. Start the Portainer container – docker run -d -p 9000:9000 portainer/portainer -H tcp://REMOTE_HOST:REMOTE_PORT
13. In a browser, navigate to the Portainer interface – http://REMOTE_HOST:REMOTE_PORT
14. Enter the default username (admin) and enter and confirm a new password

PowerShell Script to Enable/Disable Sync Rule Provisoning

I had a need to run synchronization without having provisioning on periodically and accomplishing it as a manual process wasn’t going to work. I found a script script online that looked like it might be useful.

I simplified it and made it a function to add to our scheduled run profile script.

function Set-SRProvisoning()
    set-variable -name URI -value "http://$($Server):5725/resourcemanagementservice' " -option constant
    if(@(get-pssnapin | where-object {$_.Name -eq "FIMAutomation"} ).count -eq 0) {add-pssnapin FIMAutomation}

    switch ($Enable)
        $True {$ProvisioningStatus = "sync-rule"}
        $False {$ProvisioningStatus = "none"}
        Default {Write "Bad option"}

    $exportObject = export-fimconfig -uri $URI `
                                        –onlyBaseResources `
                                        -customconfig ("/mv-data") `
                                        -ErrorVariable Err `
                                        -ErrorAction SilentlyContinue
    $provisioningState = ($exportObject.ResourceManagementObject.ResourceManagementAttributes | `
                            Where-Object {$_.AttributeName -eq "SyncConfig-provisioning-type"}).Value

    $importChange = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportChange
    $importChange.Operation = 1
    $importChange.AttributeName = "SyncConfig-provisioning-type"
    $importChange.AttributeValue = $ProvisioningStatus
    $importChange.FullyResolved = 1
    $importChange.Locale = "Invariant"
    $importObject = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportObject
    $importObject.ObjectType = $exportObject.ResourceManagementObject.ObjectType
    $importObject.TargetObjectIdentifier = $exportObject.ResourceManagementObject.ObjectIdentifier
    $importObject.SourceObjectIdentifier = $exportObject.ResourceManagementObject.ObjectIdentifier
    $importObject.State = 1 
    $importObject.Changes = (,$importChange)
    $importObject | Import-FIMConfig -uri $URI -ErrorVariable Err -ErrorAction SilentlyContinue

    switch ($Enable)
        $True {write-host "`nProvisioning enabled successfully`n"}
        $False {write-host "`nProvisioning disabled successfully`n"}

Move Hyper-V VM and Storage Files to New Location

The following script will move all of the VMs on a Hyper-V host to a new storage location. In this case we are moving the VMs from “C:\VM\VirtualMachines\” to “D:\VM\VirtualMachines\.” This script assumes that the VM disks are kept in the VM folder and not in a separate location.


foreach ($VM in $VMs)
    Move-VMStorage -VM $(Get-VM $VM.Name) -DestinationStoragePath $Path

GPG Command Line Examples

Here are some GPG examples for creating symmetric and asymmetric encrypted messages. The code used below is written for PowerShell.

Download keys from a key server

gpg --keyserver --search-keys
gpg --keyserver --recv-keys 88488596

Import private key

gpg --import ./private.asc

Put the contents of a file into a variable to be encrypted

$a = gc /etc/passwd

Symmetric encryption of the variable contents

$a | gpg --symmetric --armor
# Decrypt the message
$a | gpg --decrypt

Symmetric encryption of the variable contents with the passphrase provided

$a | gpg --symmetric --armor --passphrase password
# Decrypt the message with the passphrase provided
$a | gpg --decrypt --passphrase password

Encrypt the variable contents for a recipient

$a | gpg -e -r --armor

Decrypt the message sent to recipient

$b | gpg -d

AD Forest DCDiag and RepAdmin Report

Two earlier posts, EASY TO READ DCDIAG REPORT and EASY TO READ REPADMIN RESULTS, included scripts for displaying the high level results of DCDiag and RepAdmin. I had since combined the two and made some tweaks, but it never really seemed right.

I’ve finally gotten around to making it presentable and more functional. It now displays all of the DCDiag tests and their results in two separate tables rather than just a few of the tests that I’d selected. It also accurately displays the server name for each set of tests. The previous versions would only create reports for a single domain, but now, since I work in a multi domain forest these days, it will grab the DCs in all domains in the forest.

The RepAdmin results are now broken up by domain controller and sorted by context. This makes it a little easier to read and track issues.


# Functions 
Function Get-ForestDomainControllers
    foreach ($domain in (Get-ADForest).domains )
        $Results+=(Get-ADdomain $domain).ReplicaDirectoryServers
    Return $Results

Function Get-DCDiagReport($DC)
    "Testing $DC"
    $DCDIAG = dcdiag /s:$DC /v #/test:Intersite /test:topology
    $DCDiagResults = New-Object System.Object
    $DCDiagResults | Add-Member -name Server -Value $DC -Type NoteProperty -Force
    Foreach ($Entry in $DCDIAG) 
        Switch -Regex ($Entry) 
            "Starting" {$Testname = ($Entry -replace ".*Starting test: ").Trim()}
            "passed|failed" {If ($Entry -match "passed") {$TestStatus = "Passed"} Else {$TestStatus = "failed"}}
        If ($TestName -ne $null -and $TestStatus -ne $null) 
            $DCDiagResults | Add-Member -Type NoteProperty -name $($TestName.Trim()) -Value $TestStatus -Force
    Return $DCDiagResults

Function Get-ReplReport 
    "Starting Repadmin Tests"

    $Repl = repadmin /showrepl * /csv
    $ReplResults = $Repl | ConvertFrom-Csv 

    $ReplReport = @()

    Foreach ($result in $ReplResults) 
        $ReplReport += New-object PSObject -Property @{
            "DestSite" = $Result.'Destination DSA Site'
            "Dest" = $Result.'Destination DSA'
            "NamingContext" = $Result.'Naming Context'
            "SourceSite" = $Result.'Source DSA Site'
            "Source" = $Result.'Source DSA'
            "Transport" = $Result.'Transport Type'
            "NumberFailures" = $Result.'Number of Failures'
            "LastFailureTime" = $Result.'Last Failure Time'
            "LastSuccessTime" = $Result.'Last Success Time'
            "LastFailureStatus" = $Result.'Last Failure Status'
    Return $ReplReport

# Gather Data 

Import-Module activedirectory

"Collecting Forest Domain Controllers"

"Starting DCDiag Tests"
foreach ($DC in $DCs | sort)
    $DCDiagRpt+=Get-DCDiagReport $DC.ToUpper()

# Display Results

"Starting Repadmin Tests"

"DCDiag Test Results (Page 1 of 2)"
$DCDiagRpt | ft Server,Connectivity,Advertising,DFSREvent,SysVolCheck,KccEvent,NCSecDesc,Replications,RidManager,Services,Intersite,LocatorCheck -AutoSize
"DCDiag Test Results (Page 2 of 2)"
$DCDiagRpt | ft Server,FrsEvent,KnowsOfRoleHolders,MachineAccount,NetLogons,ObjectsReplicated,SystemLog,VerifyReferences,CheckSDRefDom,CrossRefValidation -AutoSize

"Replication Test Results"
$Servers = $ReplRrt | select -ExpandProperty Source -Unique 

foreach ($Server in ($Servers | Sort))
    $ReplRrt | ? {$_.Source -eq $Server} | select "NamingContext","Dest","SourceSite","DestSite","NumberFailures","LastFailureTime","LastFailureStatus","LastSuccessTime","Transport" | sort NamingContext,Dest | ft -AutoSize

Add Quotes and Commas to a List of Words in Bash

You have a file with a list of items and you need to put them all in quotes. All but the last line needs to have a comma at the end.

Here is the list:

$ cat testfile.txt

Use sed to make the change:

sed -i 's/^/"/; $!s/$/",/; $s/$/"/' testfile.txt

Here is the list after:

$ cat testfile.txt