LAPS.Nano.DSC.psm1
enum Ensure { Absent Present } [DscResource()] class cLapsNanoInstall { <# This resource ensures installation/uninstallation of LAPS.Nano client. All necessary files and data for LAPS.Nano client are delivered as a part of package downloaded from PS Gallery, so resource just takes files from its own package and uses them for installation Creation of DSC Configuration for this resource is pretty simple and looks like below - see Config/LAPS.Nano.DSC.Install.ps1 Ensure = Present means that resource ensures that LAPS client is installed Ensure = Absent means that resource ensures that LAPS client is uninstalled if it finds it's installed Installation status is detected as follows: - Service LAPS.Nano exists - Service executable has proper version - Service event manifest is registered For detailed instructions, see https://blogs.msdn.microsoft.com/laps/2016/05/10/laps-and-nano-server/ Sample configuration: --- $ConfigData = @{ AllNodes = @( @{ NodeName = "*" } ) } Configuration LAPS_Nano_Install { Param ( [Parameter()] [ValidateSet("Present","Absent")] [String]$Ensure = "Present" ) Import-DscResource -ModuleName LAPS.Nano.DSC -ModuleVersion '#version' cLapsNanoInstall Install { ID="LAPS.Nano" Ensure = $Ensure } } LAPS_Nano_Install -ConfigurationData $ConfigData -Ensure Present --- #> #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(($null -ne $svc) -and ($svc.Status -eq 'Running')) { Stop-Service LAPS.Nano -Force # just sleep for a while to be sure that service stops and executable is free for replacement/removal Start-Sleep -Seconds 2 } if($this.Ensure -eq [Ensure]::Present) { [String]$SourcePath = Split-Path $script:MyInvocation.MyCommand.Path if(-not [System.IO.Directory]::Exists($this.TargetFolder)) { New-Item "$($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\Messages.man" -Destination "$($this.TargetFolder)" -Force | Out-Null #LAPS event manifest registration Write-verbose '[Set] Registering LAPS.Nano ETW manifest' wevtutil um "$($this.TargetFolder)\Messages.man" wevtutil im "$($this.TargetFolder)\Messages.man" /rf:"$($this.TargetFolder)\Laps.Nano.Service.exe" /mf:"$($this.TargetFolder)\Laps.Nano.Service.exe" #Create LAPS client service - only if it does not exist if($null -eq $svc) { 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($null -ne $svc) { Write-verbose '[Set] Removing service' sc.exe delete LAPS.Nano } #unregister ETW manifest Write-verbose '[Set] Unregistering ETW manifest' if(Test-Path "$($this.TargetFolder)\Messages.man") { wevtutil um "$($this.TargetFolder)\Messages.man" } #remove service files Write-verbose '[Set] Removing LAPS binaries' Remove-Item "$($this.TargetFolder)\Messages.man" -ErrorAction SilentlyContinue Remove-Item "$($this.TargetFolder)\LAPS.Nano.Service.exe" -ErrorAction SilentlyContinue Remove-Item "$($this.TargetFolder)" -ErrorAction SilentlyContinue #we're keeping C++ runtime in place - may be used by other apps - so no removal of its binaries } 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]$serviceInstalled=$false [bool]$versionUpToDate=$false [bool]$manifestRegistered=$false #check service installation status $serviceInstalled = ($null -ne (Get-Service -Name LAPS.Nano -ErrorAction SilentlyContinue)) Write-verbose "[GetConfigStatus] ServiceInstallStatus: $serviceInstalled" #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 $versionUpToDate = (([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: $versionUpToDate" } #check event manifest registration $key=[microsoft.win32.registry]::LocalMachine.OpenSubKey('System\CurrentControlSet\Services\EventLog\Application\AdmPwd') $manifestRegistered = ($null -ne $key) Write-verbose "[GetConfigStatus] ManifestRegistrationStatus: $manifestRegistered" if($this.Ensure -eq "Present") { return $serviceInstalled -and $versionUpToDate -and $manifestRegistered } else { return -not ($serviceInstalled -or $manifestRegistered) } Write-verbose "[GetConfigStatus]Exiting" } } |