LAPS.Nano.DSC.psm1

enum Ensure
{
    Absent
    Present
}

[DscResource()]
class cLapsNanoInstall
{
    #static identifier
    [DscProperty(Key)]
    [String]$ID
    
    [DscProperty(Mandatory)]
    [Ensure] $Ensure    

    #keep file location aligned with LAPS
    [DscProperty(NotConfigurable)]
    [String]$TargetFolder="$env:ProgramFiles\AdmPwd\CSE"

    [void]Set()
    {
        Write-verbose '[Set]Entering'
        
        Write-verbose '[Set] Detecting service state and stopping, if necessary'
        $svc=Get-Service LAPS.Nano -ErrorAction:SilentlyContinue
        if($svc -ne $null -and $svc.Status -eq 'Running')
        {
            Stop-Service LAPS.Nano
        }
        if($this.Ensure -eq [Ensure]::Present)
        {
            [String]$SourcePath = Split-Path $script:MyInvocation.MyCommand.Path
            if(-not [System.IO.Directory]::Exists($this.TargetFolder))
            {
                md "$($this.TargetFolder)" -ErrorAction SilentlyContinue
            }
            #C++ runtime
            Write-verbose '[Set] Copying C++ runtime'
            if(-not (Test-Path "$env:SystemRoot\System32\vcruntime140.dll"))
            {
                Copy-Item -Path "$SourcePath\Redist\vcruntime140.dll" -Destination "$env:SystemRoot\System32" -Force | Out-Null
            }
            if(-not (Test-Path "$env:SystemRoot\System32\msvcp140.dll"))
            {
                Copy-Item -Path "$SourcePath\Redist\msvcp140.dll" -Destination "$env:SystemRoot\System32" -Force | Out-Null
            }
            
            #LAPS.Nano executable
            Write-verbose '[Set] Copying LAPS.Nano client executable'
            Copy-Item -Path "$SourcePath\Runtime\LAPS.Nano.Service.exe" -Destination "$($this.TargetFolder)" -Force | Out-Null

            #ETW manifest
            Write-verbose '[Set] Copying LAPS.Nano ETW manifest'
            Copy-Item -Path "$SourcePath\Runtime\LAPS.Nano.Service.man" -Destination "$($this.TargetFolder)" -Force | Out-Null

            #LAPS event manifest registration
            Write-verbose '[Set] Registering LAPS.Nano ETW manifest'
            wevtutil um "$($this.TargetFolder)\LAPS.Nano.Service.man"
            wevtutil im "$($this.TargetFolder)\LAPS.Nano.Service.man" /rf:"$($this.TargetFolder)\Laps.Nano.Service.exe" /mf:"$($this.TargetFolder)\Laps.Nano.Service.exe"

            #Create LAPS client service
            if($svc -eq $null)
            {
                Write-verbose '[Set] Creating service'
                New-Service -Name LAPS.Nano -BinaryPathName "$($this.TargetFolder)\LAPS.Nano.Service.exe" -DisplayName LAPS.Nano -Description "LAPS Client for Nano Server" -StartupType  Automatic | Out-Null
            }
            Write-verbose '[Set] Starting service'
            Start-Service LAPS.Nano | Out-Null  
        }
        else 
        {
            #remove service registration
            if($svc -ne $null)
            {
                Write-verbose '[Set] Removing service'
                sc.exe delete LAPS.Nano
            }
            
            #unregister ETW manifest
            Write-verbose '[Set] Unregistering ETW manifest'
            wevtutil um "$($this.TargetFolder)\LAPS.Nano.Service.man"
            
            #remove service files
            Write-verbose '[Set] Removing LAPS binaries'
            del "$($this.TargetFolder)\LAPS.Nano.Service.man" -ErrorAction SilentlyContinue
            del "$($this.TargetFolder)\LAPS.Nano.Service.exe" -ErrorAction SilentlyContinue

            rd "$($this.TargetFolder)" -ErrorAction SilentlyContinue
            
            #we're keeping C++ runtime in place - may be used by other apps

        }
        Write-verbose '[Set]Exiting'
    }
    
    [cLapsNanoInstall]Get()
    {
        Write-verbose '[Get]Entering'

        Write-verbose '[Get]Exiting'
        return $this
        
    }
    
    [bool]Test()
    {
        Write-verbose '[Test]Entering'
        
        [bool]$retVal = -$this.GetConfigStatus()

        Write-verbose "[Test]Returning $retVal"
        return $retVal
    }
    
    [bool]GetConfigStatus()
    {
        #return true is LAPS.Nano client side is properly installed
        Write-verbose "[GetConfigStatus]Entering"

        [bool]$retVal=$true
        #check service installation status
        $serviceInstalled = (Get-Service -Name LAPS.Nano -ErrorAction SilentlyContinue) -ne $null
        $retVal=$retVal -and $serviceInstalled
        Write-verbose "[GetConfigStatus] ServiceInstallStatus: $retVal"
        
        #check solution version
        #only if solution is present
        if($this.Ensure -eq 'Present' -and [System.IO.File]::Exists("$($this.TargetFolder)\LAPS.Nano.Service.exe"))
        {
               [String]$SourcePath = Split-Path $script:MyInvocation.MyCommand.Path

            $retVal = $retVal -and (([System.Diagnostics.FileVersionInfo]::GetVersionInfo("$($this.TargetFolder)\LAPS.Nano.Service.exe")).ProductVersion -ge ([System.Diagnostics.FileVersionInfo]::GetVersionInfo("$SourcePath\Runtime\LAPS.Nano.Service.exe")).ProductVersion)
            Write-verbose "[GetConfigStatus] SolutionVersionCheckStatus: $retVal"
        }

        #check event manifest registration
        $key=[microsoft.win32.registry]::LocalMachine.OpenSubKey('System\CurrentControlSet\Services\EventLog\Application\AdmPwd')
        $retVal = $retVal -and ($key -ne $null)
        Write-verbose "[GetConfigStatus] ManifestRegistrationStatus: $retVal"
        
        if($this.Ensure -eq "Present")
        {
            return $retVal
        }
        else
        {
            return -not $retVal
        }
        Write-verbose "[GetConfigStatus]Exiting"
    }
}