How to use certutil output as Objects within PowerShell

Working with Certification Authorities (CA), native PowerShell commands are not too well established yet to fit all my needs, so I had to think about a solution how I could use the well-known certutil tool and use its output within PowerShell.

That is what I came up with (thanks to Shane’s blogpost):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
function certutilToObjectList($certutilOutput){
 
    $certutilObjectList = @()
    $currentKey = $null
    $currentValue = $null
    $certutilOutput -split [environment]::NewLine | foreach {
 
        switch -regex ($_){
 
            '[Entry|Row] \d+:(.*)' {
                # New Object found
                $currentObject = New-Object psobject
                $currentValue = $null
                continue
            }
 
            '(\s{2})(?[\w\s]+):\s*(?.*)' {
                # Add key / value pair to Object
                if($currentObject){ 
                    if( -not $matches.value){
                        $currentKey = $matches.key.Trim()
                        $currentValue = $null
                    }
                    else {
                        $currentObject | Add-Member -MemberType NoteProperty -Name $($matches.key.Trim()) -Value $($matches.value.trim(@("'",'"','`'))) -Force 
                    }
                }
            }
 
            '^$' {
                # Add Object to ObjectList if Object exists
                if($currentObject){ 
                    if($currentKey -and $currentValue){
                        $currentObject | Add-Member -MemberType NoteProperty -Name $($currentKey) -Value $($currentValue) -Force 
                    }
                    $certutilObjectList += $currentObject 
                    $currentObject = $null
                    $currentKey = $null
                    $currentValue = $null
                }
            }
 
            default {
                # Save Values of Multiline Parameters if a current Key exists
                if($currentObject -and $currentKey){ 
                    $currentValue += $_+"`n"
                }
            }
        }
    }
 
    # Add last Object to ObjectList if necessary
    if($currentKey -and $currentValue){
        $currentObject | Add-Member -MemberType NoteProperty -Name $($currentKey) -Value $($currentValue) -Force 
    }
    $certutilObjectList += $currentObject
 
    return $certutilObjectList
}
 
 
$certutil = "$($env:SystemRoot)\system32\certutil.exe"
$certutilOutput = Invoke-Expression "$certutil -view -restrict disposition==20 -out 'serialnumber,requestid,Issued Common Name,Certificate Expiration Date'"
$certutilObjectList = certutilToObjectList $certutilOutput

This function splits the certutil output into single rows and processes them one by one using regular expressions to figure out what to do with each row. It further creates a list (array) of PowerShell objects to make the output easily usable with PowerShell.

Read More

How to change your Password in a Remote Session (Windows Security)

Using a jump server to connect from your computer to different servers in your network makes it quite uncomfortable to change your password in a Windows Server 2012 environment.

Pressing Ctrl + Alt + End (instead of Delete) opens Windows Security on the jump server and not on the server you are remoting on using the jump server.

There is an easy solution, though: create a new .vbs file on the remote computer i.e. “WindowsSecurity.vbs” and add the following code:

1
2
Set objShell = CreateObject("Shell.Application")
objShell.WindowsSecurity

Now all you have to do is just double click the file and Windows Security pops up which allows you to change your password.

Creating a ZIP Archive with PowerShell Version <5.0

The PowerShell command “Compress-Archive” comes pretty handy when it comes to creating a .zip file/archive. Sadly it only available since PowerShell version 5.0. which comes with Windows 10 (can be installed on Windows 8.1 and Windows Server 2012 R2 as well, though).
No worries, there is a solution as well which works with Powershell <5.0. The following function requires the output filename e.g. "C:\temp\MyOutputArchive.zip" and the full path of the directory to be archived eg. "C:\temp\ToBeArchived\".

1
2
3
4
5
function createZipFile($outputFileName, $sourceDirectory){
    Add-Type -AssemblyName System.IO.Compression.FileSystem
    $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
    [System.IO.Compression.ZipFile]::CreateFromDirectory($sourceDirectory, $outputFileName, $compressionLevel, $false)
}

Simple PowerShell Logging Function

I use this simple PowerShell logging function in multiple smaller scripts of mine to write a hourly logfile with a generic name in a specific path.

As an input it takes the two parameters “message” and “severity”. The later is optional and set to “INFO” by default. It further needs the (global) variable $logPath which should be defined and filled with the full path to where the logfile should be stored on the filesystem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Define the log output directory
$logPath = "C:\temp\log"
 
# Simple Logging Function
function Write-Log(){
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true)]
        [String]
        $message = "INFO",
 
        [Parameter(Mandatory = $false)]
        [ValidateSet("INFO","WARN","ERROR","DEBUG")]
        [String]
        $severity = "INFO"
    )
 
    # Define Output Color
    $color = "white"
    if($severity -eq "WARN"){
        $color = "yellow"
    }
    elseif($severity -eq "ERROR"){
        $color = "red"
    }
    elseif($severity -eq "DEBUG"){
        $color = "cyan"
    }
 
    # Create Log Directory if not exists
    if(!(Test-Path $global:logPath)){
        New-Item -ItemType Directory -Path $global:logPath
        Write-Log "Log Directory '$($global:logPath)' created"
    }
 
    # Prepare Log Line
    $logLine = "$(Get-Date -format "dd.MM.yyyy HH:mm:ss") `t $($severity) `t $($message)"
 
    # Write Logfile
    $scriptName = ((($MyInvocation.ScriptName -split ("\\"))[($MyInvocation.ScriptName -split ("\\")).Length -1]) -replace ".ps1", "").ToLower()
    $logFileName = "log_$($scriptName)_$(Get-Date -format "yyyy-MM-dd-HH").log"
    $logLine | Out-File -FilePath "$($global:logPath)\$logFileName" -Append -Encoding utf8
 
    # Print Logline
    Write-Host $logLine -ForegroundColor $color
}
 
#Test it
Write-Log "My Message" 
Write-Log "My Warning Message" "WARN"
Write-Log "My Error Message" "ERROR"
Write-Log "My Debug Message" "DEBUG"

How to create a Scheduled Task using PowerShell

Working with group Managed Service Accounts gMSA (not a topic of this post) and Scheduled Tasks, you’ll figure pretty soon that creating a Scheduled Task using the MMC Snap-in does not get you too far. As a solution: just create your Scheduled Task using Powershell.

I’m therefore using the code below. Just adjust it to your needs as required.

1
2
3
4
5
6
7
8
$taskName = "My Scheduled Task"
$taskDesc = "My fanc description"
$actionArgs = '-file "C:\Path\to\my\Script.ps1"'
$taskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $actionArgs 
$taskTrigger = New-ScheduledTaskTrigger -Daily -At 8:30pm
$taskSettings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 60) -RestartCount 2 -RestartInterval (New-TimeSpan -Minutes 15) -RunOnlyIfNetworkAvailable -Compatibility "Win8"
$taskPrincipal = New-ScheduledTaskPrincipal -UserID "CUSTOMERS\svcgMSA_Task$" -LogonType Password -RunLevel Highest
Register-ScheduledTask -TaskName $taskName -Description $taskDesc -Action $taskAction -Trigger $taskTrigger -Settings $taskSettings -Principal $taskPrincipal