ADLAB PowerShell source file: buildup-2.ps1

(C) Ondrej Sevecek, 2019 - www.sevecek.com, ondrej@sevecek.com



#=====================
# Common machine config

DBG ("Build step: {0}" -f $MyInvocation.MyCommand.Definition)
DBG "Common machine config..."


#===============
DBG ("Change video resolution: {0} | {1}" -f (Is-ValidString ($vmConfig.commonVM.videoRes)), $vmConfig.commonVM.videoRes)

if (Is-ValidString ($vmConfig.commonVM.videoRes)) {

  $videResWidthHeight = Split-MultiValue $vmConfig.commonVM.videoRes
  [int] $videoWidth = Parse-IntSafe $videResWidthHeight[0]
  [int] $videoHeight = Parse-IntSafe $videResWidthHeight[1]
  DBG ('Requested video resolution: {0} x {1}' -f $videoWidth, $videoHeight)

  Define-Win32Api
  $win32rs = [Sevecek.Win32Api.User32]::ChangeDisplaySettings_Implemented($videoWidth, $videoHeight)
  DBGIF ('Change video resolution failed with: {0}' -f $win32rs) { $win32rs -ne 0 }
}



#===============
DBG ("Disable NetBIOS: {0}" -f (Parse-BoolSafe($vmConfig.commonVM.netbiosOff)))

if (Parse-BoolSafe($vmConfig.commonVM.netbiosOff))
{
  $nics = Get-WMIQueryArray '.' "SELECT * FROM Win32_NetworkAdapterConfiguration"
  
  $nics | % { 

    DBG ("Disabling NetBIOS on NIC: {0}, {1}" -f $_.Index, $_.Description)
    DBGSTART
    $wmiRs = $null
    $wmiRs = $_.SetTcpipNetbios(2)
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND
    DBGWMI $wmiRs
  }
}


#=================
DBG ("Going to initialize preconfigured HDDs")

#$offlineHDDs = Get-WMIQueryArray '.' "SELECT * FROM Win32_DiskDrive WHERE Signature = '0' OR Signature = NULL" | Sort-Object Index
$initializedHDDs = Get-WMIQueryArray '.' "SELECT * FROM Win32_DiskDrive" | Sort-Object Index
DBG ('Found all HDDs: {0}' -f $initializedHDDs.Count)

DBG ('Determine OS disk: {0}' -f $env:SystemDrive)
$osLogicalDisk = Get-WmiQuerySingleObject '.' ('SELECT * FROM Win32_LogicalDisk WHERE DeviceId = "{0}"' -f $env:SystemDrive)
$osPartition = Get-WmiRelated $osLogicalDisk 'Win32_DiskPartition'
[int] $osDiskIndex = $osPartition.DiskIndex
DBG ('OS disk determined as: {0}' -f $osDiskIndex)
DBGIF $MyInvocation.MyCommand.Name { Is-Null $osLogicalDisk }
DBGIF $MyInvocation.MyCommand.Name { Is-Null $osPartition }


foreach ($oneHDD in $initializedHDDs) {

  $diskID = $oneHDD.index
  
  DBG ("Processing disk: {0}, {1}, {2}, {3}, {4}, {5}, {6}" -f $oneHDD.Index, $oneHDD.InterfaceType, $oneHDD.Signature, ([int] ($oneHDD.Size / 1024 / 1024 / 1024)), $oneHDD.Caption, $oneHDD.Partitions, $oneHDD.DeviceID)
  DBGIF $MyInvocation.MyCommand.Name { ($oneHDD.InterfaceType -ne 'IDE') -and ($oneHDD.InterfaceType -ne 'SCSI') -and ($oneHDD.InterfaceType -ne 'HDC') -and ($oneHDD.InterfaceType -ne 'USB') -and ($oneHDD.InterfaceType -ne '1394') }


  [bool] $shouldSkipTheDisk = $oneHDD.Index -eq $osDiskIndex
  DBG ('Check if we should exclude this disk from being initialized: {0}' -f $shouldSkipTheDisk)

  if (-not $shouldSkipTheDisk) {

    $oneHDDPartitions = Get-WMIRelated $oneHDD 'Win32_DiskPartition'
 
    if ((Get-CountSafe $oneHDDPartitions) -gt 0) {

      foreach ($oneHddPartition in $oneHDDPartitions) {

        $oneHddLogicalDisks = Get-WMIRelated $oneHddPartition 'Win32_LogicalDisk'

        if ((Get-CountSafe $oneHddLogicalDisks) -gt 0) {

          foreach ($oneHddLogicalDisk in $oneHddLogicalDisks) {

            $possibleNoInitializationMarker = Join-Path $oneHddLogicalDisk.DeviceId $global:diskNoInitialization
            DBG ('One possible no-init marker: {0}' -f $possibleNoInitializationMarker)

            if (Test-Path $possibleNoInitializationMarker) {
     
              DBG ('Found a disk volume which excludes the disk from being initialized: {0}' -f $oneHddLogicalDisk.DeviceId)
              $shouldSkipTheDisk = $true
            }
          }
        }
      }   
    }
  }


  if (($oneHDD.Partitions -gt 0) -and ($oneHDD.InterfaceType -ne 'IDE') -and (-not $shouldSkipTheDisk)) {
    

    if ($thisOSVersion -like '5.*') {

      # Will not online the disk on Windows XP as the OS
      # does not support SCSI media in Hyper-V IC.
      # but proceeds without an error
      $diskPartScr = @"
list disk
select disk $diskID
online noerr
"@
    }
  
    else {
  
      # Note: Win6.x mounts the disks as read/only by default
      $diskPartScr = @"
list disk
select disk $diskID
online disk noerr
attributes disk clear readonly
"@
    }

    #$diskPartScrFile = Get-DataFileApp 'disk-part-online-disk' $null '.txt'
    #$diskPartScr.Replace("`n", "`r`n") | Set-Content -Path $diskPartScrFile -Force -EV er -EA SilentlyContinue
    #DBGER $MyInvocation.MyCommand.Name $er

    DBG ('Bring the disk ONLINE')
    # 0x80042807 = disk already online or rather cannot clear read/only attribute everywhere 6.1+
    # 0x4 = cannot clear read/only attribute on 6.0
    Call-DiskPart $diskPartScr ('disk-part-online-disk-{0:D2}' -f $oneHDD.Index) #@(0x80042807)
    #Run-Process 'DISKPART' ('/s "{0}"' -f $diskPartScrFile) -ignoreExitCodes @(0x80042807)

    DBG ("Giving it 4sec to assign a letter in a correct sequence if it happens automatically")  
    Start-Sleep 4

    
    if ($global:thisOSVersionNumber -lt 6) {

      # Note: On Windows 2003, the letters are not assigned automatically,
      #       at least not on clean ISO install of 2003 R2
      #
      $nonAssignedVolumes = Get-WMIQueryArray '.' 'SELECT * FROM Win32_Volume WHERE DriveLetter IS NULL AND Label <> "System Reserved"'
      DBG ('Found some volumes without assigned letters: {0}' -f (Get-CountSafe $nonAssignedVolumes))

      foreach ($oneNonAssignedVolume in $nonAssignedVolumes) {

        DBG ('Assign next free drive letter to: {0}' -f $oneNonAssignedVolume.DeviceId)
        DBGSTART
        $wmiRs = $null
        $wmiRs = $oneNonAssignedVolume.AddMountPoint(('{0}:\' -f (Get-NextFreeDriveLetter)))
        DBGER $MyInvocation.MyCommand.Name $error
        DBGEND
        DBGWMI $wmiRs
      }
    }

  } else {

    DBG ('Skipping the disk as it either does not have any partitions on it, or is IDE attached, or is a system disk or is explicitly excluded')
  }
}


#=================
DBG ('Going to initialize data HDDs from empty HDDs')

$localAppDisks = ($vmConfig.SelectNodes('./*/app[@disks>0]') | Measure-Object -Maximum disks).Maximum
DBG ('Initialize APP required data disks: {0}' -f ($localAppDisks))

if ($localAppDisks -gt 0) {

  $emptyHDDs = (Get-WMIQueryArray '.' "SELECT * FROM Win32_DiskDrive WHERE Partitions = '0'") | Sort-Object Index | Select-Object -First $localAppDisks
  # Note: in case the originally returned WMIQueryArray has just a single item, the Sort-Object and Select-Object
  #       fucking behavior is to convert the result to a non-array. We cannot improve it with operator (,) as
  #       it would create multidim array in the other cases. This sucks
  DBG ('Found empty HDDs: {0}' -f (Get-CountSafe $emptyHDDs))

  $dataDiskId = 0
  foreach ($oneHDD in $emptyHDDs) {
    
    $dataDiskId ++

    if ($global:adaptingExistingEnv) {

      DBG ('We are adapting already build environment so check if a disk with the diskID is not already attached: {0}' -f $dataDiskId)
      [string] $markedVolumeDriveFound = Find-MarkedVolume ($global:datadiskMarker -f $dataDiskId) -driveType 3
      if (Is-ValidString $markedVolumeDriveFound) {

        DBG ('We have found an already build data disk: {0}' -f $markedVolumeDriveFound)
        continue
      }
    }

    DBG ("Processing disk: {0}, {1}, {2}, {3}, {4}, {5}, {6}" -f $oneHDD.Index, $oneHDD.InterfaceType, $oneHDD.Signature, ([int] ($oneHDD.Size / 1024 / 1024 / 1024)), $oneHDD.Caption, $oneHDD.Partitions, $oneHDD.DeviceID)
    DBGIF $MyInvocation.MyCommand.Name { $oneHDD.InterfaceType -ne 'SCSI' }
    
    $diskID = $oneHDD.index
    $diskDeviceID = $oneHDD.DeviceID
    
    if ($thisOSVersion -like '5.*') {

      $diskPartScr = @"
select disk $diskID
online noerr
convert gpt noerr
create partition primary noerr
assign noerr
"@
    }
  
    else {
  
      # Note: Win6.x mounts the disks as read/only by default
      $diskPartScr = @"
select disk $diskID
online disk noerr
attributes disk clear readonly noerr
convert gpt noerr
create partition primary noerr
assign noerr
"@
    }

    #$diskPartScrFile = Get-DataFileApp 'disk-part-online-data-disk' $null '.txt'
    #$diskPartScr.Replace("`n", "`r`n") | Set-Content -Path $diskPartScrFile -Force -EV er -EA SilentlyContinue
    #DBGER $MyInvocation.MyCommand.Name $er

    DBG ('Bring the empty disk ONLINE and create new PARTITION')
    #Run-Process 'DISKPART' ('/s "{0}"' -f $diskPartScrFile)
    Call-DiskPart $diskPartScr 'disk-part-online-data-disk'

    DBG ("Giving it 4sec to assign a letter in a correct sequence")  
    Start-Sleep 4

    DBG ('Find the assigned partition.')
    $newPartition = Get-WMIQuerySingleObject '.' ('Associators Of {{Win32_DiskDrive.DeviceID="{0}"}} WHERE ResultClass = Win32_DiskPartition' -f ($diskDeviceID.Replace('\', '\\')))
    
    DBG ('Find the assigned letter.')
    $logicalDisk = Get-WMIQuerySingleObject '.' ('Associators Of {{Win32_DiskPartition.DeviceID="{0}"}} WHERE ResultClass = Win32_LogicalDisk' -f ($newPartition.DeviceID.Replace('\', '\\')))
    DBG ('Letter determined: {0}' -f $logicalDisk.DeviceID)

    $newVolume = Get-WMIQuerySingleObject '.' ('SELECT * FROM Win32_Volume WHERE DriveLetter = "{0}" AND FileSystem = NULL' -f $logicalDisk.DeviceID)

    if (Is-NonNull $newVolume) {

      DBG ('Format volume: {0} | {1}' -f $newVolume.DriveLetter, $newVolume.DeviceID)

      DBGSTART
      $wmiRs = $null
      $wmiRs = $newVolume.Format('NTFS', $true, 0, "DATA$dataDiskId", $false)
      DBGER $MyInvocation.MyCommand.Name $error
      DBGEND
      DBGWMI $wmiRs

      DBG ('Create ID file')
      New-Item -Path (Join-Path $logicalDisk.DeviceID ($global:datadiskMarker -f $dataDiskId)) -ItemType File -Force -EV er -EA SilentlyContinue | Out-Null
      DBGER $MyInvocation.MyCommand.Name $er
    }
  }
}


Find-MarkedVolumes


#===============
DBG ('Create all partitions required')
$partitions = $vmConfig.SelectNodes('./*/partition')
DBG ('Found partition requirements: {0}' -f (Get-CountSafe $partitions))

if ((Get-CountSafe $partitions) -gt 0) {

  foreach ($onePartition in $partitions) {

    DBG ('One partition: doNotCreate = {0} | letter = {1}' -f (-not (Parse-BoolSafe $onePartition.existing)), $onePartition.letter)
    
    if (-not (Parse-BoolSafe $onePartition.existing)) {

      Create-Partition $onePartition
    }
  }
}



#===============
DBG ('Update ISO disk letters')

if (Is-ValidString $vmConfig.vm.iso) {

   $isos = Split-MultiValue $vmConfig.vm.iso

   DBG ('Found ISOs in config: {0}' -f (Get-CountSafe $isos))

   $cdDeviceNumber = 0
   foreach ($oneISO in $isos) {

     [string] $newDriveLetterPlusMarker = ''

     if (Has-ValueFlags $oneISO D ([ref] $newDriveLetterPlusMarker)) {

       $isoMarker = $newDriveLetterPlusMarker.SubString(1)
       $newDriveLetter = $newDriveLetterPlusMarker.SubString(0, 1)
       DBG ('ISO should be assigned drive letter: {0} | {1} | {2} | {3}' -f $cdDeviceNumber, $isoMarker, $oneISO, $newDriveLetter)

       [string] $currentDrive = '' # must be typed explicitly, because the latter .Drive[0] produces [char] instead of [string]
       if (Is-ValidString $isoMarker) {

         $currentDrive = (Find-MarkedVolume $isoMarker 5)[0]
       }
       
       if (Is-EmptyString $currentDrive) {

         # there might not be the ISO yet, in case nothing is found, we proceed with CDROM drive number method
         $currentDrive = (Get-WmiQueryArray '.' 'SELECT * FROM Win32_CDRomDrive')[$cdDeviceNumber].Drive[0]
       }

       DBG ('ISO found at: {0}' -f $currentDrive)
       DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $currentDrive }

       if (Is-ValidString $currentDrive) {

         if ($global:thisOSVersionNumber -eq 5.1) {

           # Note: on Windows XP, the Win32_Volume is not available so we have to make do with MOUNTVOL command instead
           DBG ('Remounting the drive with MOUNTVOL on Windows XP')
           $mountvolCmdPath = "$env:SystemRoot\System32\mountvol.exe"

           $mountvolOutput = (& $mountvolCmdPath ('{0}:\' -f $currentDrive) '/L')
           DBG ('MOUNTVOL output: {0}' -f ($mountvolOutput | Out-String))

           $currentDriveSystemPath = $mountvolOutput.Trim()
           DBG ('Current drive system path: {0}' -f $currentDriveSystemPath)

           DBGIF $MyInvocation.MyCommand.Name { $currentDriveSystemPath -notmatch "\\\\\?\\Volume{$global:rxGUID}\\" }

           Run-Process $mountvolCmdPath ('"{0}:" /D' -f $currentDrive)
           Run-Process $mountvolCmdPath ('"{0}:" "{1}"' -f $newDriveLetter, $currentDriveSystemPath.SubString(0, ($currentDriveSystemPath.Length - 1)))

         } else {
 
           $isoVolume = Get-WmiQuerySingleObject '.' ('SELECT * FROM Win32_Volume WHERE DriveLetter = "{0}:"' -f $currentDrive)

           DBG ('ISO volume found: {0} | {1} | {2}' -f $isoVolume.Label, $isoVolume.DriveLetter, $isoVolume.FileSystem)

           DBG ('Set new drive letter: {0}' -f $newDriveLetter)
           DBGSTART
           $isoVolume.DriveLetter = '{0}:' -f $newDriveLetter
           $wmiRes = $isoVolume.Put()
           DBGER $MyInvocation.MyCommand.Name $error
           DBGEND
        }
       }
     }

     $cdDeviceNumber ++
   }
}



#===============
DBG ("Will update installation source paths: {0}" -f ($thisOSVersion -like '5.*'))

if ($thisOSVersion -like '5.*') {

  if ($thisOSRole -like '*workstation*') {

    DBG ('Clients get installed from DVD, find the installation media for Windows XP')
    $winSrcPath = Find-MarkedVolume 'WIN51' 5
    DBGIF $MyInvocation.MyCommand.Name { $winSrcPath -ne (Find-MarkedVolume 'SETUP.EXE' 5) }
    DBGIF $MyInvocation.MyCommand.Name { $winSrcPath -ne (Find-MarkedVolume 'i386' 5) }
    DBG ("Updating source paths for XP: {0}, i386 exists = {1}" -f $winSrcPath, (Test-Path (Join-Path $winSrcPath i386)))
  }
  
  else {
  
    # WinSrcPath was originally pointing to DISK1, but we need to have both Disk1 and Disk2 in the same location
    # to allow for SYSOCMGR installation of R2 components
    #$winSrcPath = Join-Path $installMediaVolume 'Windows2003R2-SP2\win2k3r2-withsp2-disk1'
    $winSrcPath = Join-Path $installMediaVolume 'Windows2003R2-SP2'

    if (-not (Test-Path (Join-Path $winSrcPath i386))) {

        # FUCK LAZY JUNG, I have updated the installMedia.VHD but the lazy pig didn't updated the image

        DBG ('Path does not exist: {0}' -f (Join-Path $winSrcPath i386))

        $winSrcPath = Join-Path $installMediaVolume 'Windows2003R2-SP2\win2k3r2-withsp2-disk1'
        DBG ('Fall back to older installation media path (FUCK LAZY JUNG): {0}' -f $winSrcPath)
    }


    DBG ("Updating source paths for 2003: {0}, i386 exists = {1}" -f $winSrcPath,(Test-Path (Join-Path $winSrcPath i386)))
  }

  Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup' SourcePath $winSrcPath String
  Set-RegistryValue 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup' ServicePackSourcePath $winSrcPath String
}


DBG ('Cleanup filler files from all volumes')
do {

  $fillerFound = ''
  $fillerFound = Find-MarkedVolume $global:emptyFiller 3

  if (Is-ValidString $fillerFound) {

    DBG ('Remove filler file: {0}' -f $fillerFound)
    DBGSTART
    Remove-Item "$fillerFound\$global:emptyFiller" -EA SilentlyContinue
    if ($error.Count -gt 0) { $notDeleted = $true }
    DBGER $MyInvocation.MyCommand.Name $error
    DBGEND

    if ($notDeleted) {

      DBGIF 'Stopping filler deletions to prevent looping on a file that cannot be deleted' { $notDeleted }
      break
    }

  } else {

    DBG ('No other filler file found')
  }

} while (Is-ValidString $fillerFound)



DBG ('Should update PATH variable: {0}' -f (Is-ValidString $vmConfig.commonVM.path))
if (Is-ValidString $vmConfig.commonVM.path) {

  [string[]] $pathItems = Split-MultiValue $vmConfig.commonVM.path
  DBG ('Path items to add: {0}' -f $pathItems.Count)

  foreach ($onePathItem in $pathItems) {

    Set-EnvironmentVariable 'PATH' (Resolve-VolumePath (Strip-ValueFlags $onePathItem)) 'Machine' $true $true
  }
}



DBG ('Should mark install media volume(s) read/only: {0}' -f (Parse-BoolSafe $vmConfig.commonVM.installMediaRO))
if (Parse-BoolSafe $vmConfig.commonVM.installMediaRO) {

  $allInstallMediaVolumes = Find-MarkedVolume $global:installSourceMediaWildcard 3 -findAllWithWildcard

  foreach ($oneInstallMediaVolume in $allInstallMediaVolumes) {

    $imLD = Get-WmiQuerySingleObject '.' ('SELECT * FROM Win32_LogicalDisk WHERE DeviceId = "{0}"' -f $oneInstallMediaVolume)
    $imDP = Get-WmiRelatedSingle $imLD 'Win32_DiskPartition'
    $imDD = Get-WmiRelatedSingle $imDP 'Win32_DiskDrive'

    DBG ('Install media volume/partition/disk: {0} | {1} | {2} | {3} | {4} | {5} | {6} | {7}' -f $imLD.VolumeName, [Math]::Round(($imLD.Size / 1GB), 1), [Math]::Round(($imLD.FreeSpace / 1GB), 1), $imDP.Name, $imDP.BootPartition, $imDD.Name, $imDD.Index, $imDD.Signature)
    $imDiskId = $imDD.Index
    DBG ('Install media disk index found: {0}' -f $imDiskId)

    DBGIF $MyInvocation.MyCommand.Name { $imDP.Name -notlike ('Disk #{0}, Partition #*' -f $imDiskId) }
    DBGIF $MyInvocation.MyCommand.Name { $imDD.Name -notlike ('\\.\PHYSICALDRIVE{0}' -f $imDiskId) }

    if ($global:thisOSVersionNumber -gt 5.2) {

      $diskPartScr = @"
SELECT DISK $imDiskId
ATTRIBUTES DISK SET READONLY
"@

      Call-DiskPart $diskPartScr "disk-part-mark-install-media-read-only"
  
    } else {

      DBG ('Cannot use DISKPART ATTRIBUTES on Windows XP and older')
      DBG ('Cannot use DISKPART ATTRIBUTES DISK on Windows 2003')
      DBG ('Leaving install media writable as long as its permissions allow')
    }
  }
}


DBG ('Should we extend some volumes: {0} | {1}' -f (Is-ValidString $vmConfig.wks.extendVol), $vmConfig.wks.extendVol)
if (Is-ValidString $vmConfig.wks.extendVol) {

  [string[]] $volumes = Split-MultiValue $vmConfig.wks.extendVol
  DBG ('Volumes to be extended: #{0} | {1}' -f $volumes.Length, ($volumes -join ','))

  foreach ($oneVolume in $volumes) {

    $oneVolumeDisk = Split-Path -Qualifier (Resolve-VolumePath $oneVolume)
    DBGIF ('Weird volume path: {0}' -f $oneVolumeDisk) { $oneVolumeDisk -notlike '[a-z]:' }

    [string] $diskPartScr = @"
SELECT VOLUME $oneVolumeDisk
EXTEND
"@

    Call-DiskPart $diskPartScr 'disk-part-extend-volume'
  }
}


DBG ('Should we enhost all host IP addresses: {0}' -f (Parse-BoolSafe $vmConfig.commonVM.hostTheHost))
if (Parse-BoolSafe $vmConfig.commonVM.hostTheHost) {

  DBG ('Host IP addresses: {0} | {1}' -f $global:phaseCfg.sevecekBuildup.host.ips, (Count-MultiValue $global:phaseCfg.sevecekBuildup.host.ips))
  $hostIPs = Split-MultiValue $global:phaseCfg.sevecekBuildup.host.ips
  DBGIF $MyInvocation.MyCommand.Name { (-not $global:adaptingExistingEnv) -and (Get-CountSafe $hostIPs) -lt 1 }

  if ((Get-CountSafe $hostIPs) -gt 0) {

    $atLeastOneIPv4Done = $false
    foreach ($oneHostIP in $hostIPs) {

      DBG ('One IP to host: {0}' -f $oneHostIP)
      DBGIF ('Weird IP address: {0}' -f $oneHostIP) { -not (Is-IPv4OrIPv6Address $oneHostIP) }
      
      if ($oneHostIP -match $global:rxIPv4) {

        $nameAndIPs = @{ 'hvhost' = ('A${0}' -f $oneHostIP) }
        Update-HostsFile $nameAndIPs
        $atLeastOneIPv4Done = $true
      }
    }

    DBGIF $MyInvocation.MyCommand.Name { -not $atLeastOneIPv4Done }
  }
}


DBG ('Should we configure monitor off and desktop lockout times manually: {0} | {1}' -f (Is-ValidString $vmConfig.monitorOff), $vmConfig.monitorOff)
if (Is-ValidString $vmConfig.monitorOff) {

  Set-MonitorLockTimeout $vmConfig.monitorOff

  if ($global:thisOSVersionNumber -ge 6.2) {

    DBG ('Set the registry value to show the console lock timeout in the power control panel on Windows 6.2+')
    Set-RegistryValue 'HKLM:\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\7516b95f-f776-4464-8c53-06167f40cc99\8EC4B3A5-6868-48c2-BE75-4F3044BE88A7' Attributes 2 DWord
  }
}


#=================
DBG ('Disable Windows Welcome Tour on Windows XP: {0}' -f (Parse-BoolSafe $vmConfig.noWelcomeTour))

if (Parse-BoolSafe $vmConfig.noWelcomeTour) {

  DBGIF $MyInvocation.MyCommand.Name { ($global:thisOSVersionNumber -gt 5.2) -or ($global:thisOSRole -notlike '*Workstation*') }
  Set-RegistryValue 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Applets\Tour' RunCount 0 DWord
}


#=================
DBG ('Disable Sidebar on Windows Vista: {0}' -f (Parse-BoolSafe $vmConfig.sidebarOff))

if (Parse-BoolSafe $vmConfig.sidebarOff) {

  DBGIF $MyInvocation.MyCommand.Name { ($global:thisOSVersionNumber -ne 6.0) -or ($global:thisOSRole -notlike '*Workstation*') }
  Set-RegistryValue 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\Windows\Sidebar' TurnOffSidebar 1 DWord
}





# SIG # Begin signature block
# MIIc/QYJKoZIhvcNAQcCoIIc7jCCHOoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBk1zOR6E7YtjPo
# bvTyWkGidb0cc/GET3uN3dihzxclm6CCGAQwggTlMIIDzaADAgECAhA5vUKe0oFu
# utW8yQO0umXnMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNVBAYTAklMMRYwFAYDVQQK
# Ew1TdGFydENvbSBMdGQuMSkwJwYDVQQLEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9u
# IEF1dGhvcml0eTEjMCEGA1UEAxMaU3RhcnRDb20gQ2xhc3MgMiBPYmplY3QgQ0Ew
# HhcNMTYxMjAxMTU1MTEzWhcNMTgxMjAxMTU1MTEzWjBRMQswCQYDVQQGEwJDWjEa
# MBgGA1UECAwRSmlob21vcmF2c2t5IEtyYWoxDTALBgNVBAcMBEJybm8xFzAVBgNV
# BAMMDk9uZHJlaiBTZXZlY2VrMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
# AQEAr9E9hNj06bash9JX97kpsqK9Z/ciOBC6trI4nvlW9CPwhKBTb5wArhxLYZBG
# 9jWPWrdy1nL/cm5qMqBb/mogYwMwvEYWMvsIOOVn6HD9lVhNAovD6PHz0ziBBKIs
# zXTjyUPQaoIlIELovz967m78HJdUZJGxqhluAsS9o9/fEzA7XXUhUuqRKsetuZV/
# Asfh5sOveeoRsbeW4daTWvtz3TJuULL0w43LNVYJkd6LL8cegvLPVZUe1N7skvid
# EvntdlowQsJlqFdrH3SGKIPKA6ObcY8SZWkEQSbVBF8Kum1UT+jN0gm+84FwOg5W
# qKx+VvTK2ljVWnPrCD0Zzu2oIQIDAQABo4IBkzCCAY8wDgYDVR0PAQH/BAQDAgeA
# MBMGA1UdJQQMMAoGCCsGAQUFBwMDMAkGA1UdEwQCMAAwHQYDVR0OBBYEFG2vSo3N
# hQWILeUs0oN9XzHTejcfMB8GA1UdIwQYMBaAFD5ik5rXxxnuPo9JEIVVFSDjlIQc
# MG0GCCsGAQUFBwEBBGEwXzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Auc3RhcnRz
# c2wuY29tMDcGCCsGAQUFBzAChitodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0
# cy9zY2EuY29kZTIuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuc3Rh
# cnRzc2wuY29tL3NjYS1jb2RlMi5jcmwwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5z
# dGFydHNzbC5jb20vMFEGA1UdIARKMEgwCAYGZ4EMAQQBMDwGCysGAQQBgbU3AQIF
# MC0wKwYIKwYBBQUHAgEWH2h0dHBzOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kw
# DQYJKoZIhvcNAQELBQADggEBAJuRiEvHtIYSpsmMkPhTz4QOOShN3p5KWdf8vm71
# A33CR9fds10d8D2B2aE+vjmHJ69GY0bbfg5oZY2Lsq2euL7Da5/hS8+6T3MEtD4h
# njfHV7mxmoSfFuy/KDipoV6uwhI+ksqchXYdUH+5uCQO0MOO8ITjAgzUQsnZ4UIB
# HBGeP+e+3ljxSYSXWdPIrgxdR971P/HhWSVfKNlmBgEKMQM5Jy0aAd4jxSl/AzdY
# t0+6pliFJ1peGhdFni2Fm8fu5oN68aTIrNtc5WY7Lzgf+sRTVeWORWS37+1zAD0m
# jzd8gyfBLxRuaRSfjYxny0rLXelAwfiA3ze2DU2Bfg9/rfcwggXYMIIDwKADAgEC
# AhBsO9J+3TyUnpWOKKmzx1egMA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAklM
# MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRh
# bCBDZXJ0aWZpY2F0ZSBTaWduaW5nMSkwJwYDVQQDEyBTdGFydENvbSBDZXJ0aWZp
# Y2F0aW9uIEF1dGhvcml0eTAeFw0xNTEyMTYwMTAwMDVaFw0zMDEyMTYwMTAwMDVa
# MHUxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSkwJwYDVQQL
# EyBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEjMCEGA1UEAxMaU3Rh
# cnRDb20gQ2xhc3MgMiBPYmplY3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
# ggEKAoIBAQC5FARY97LFhiwIMmCtCCbAgXe5aBnZFSsdGGnk2hqWBZcuZHkaqT1R
# M1rQd2r0ApNBw466cBur2Ht0b5jo17mpPmh2pImgIqwX1in4u7hhn9IH0GYOMEcg
# K3ACHv5zCRxxNLXifqmsqKfxjjpABnaSyvd4bO9YBXN9f4NQ6aJVAuMArpanxsJk
# e+P4WECVLk17v92CAN5JVaczI+baT/lgo5NVcTEkloCViSbIfU6ILeyhOSQZvpom
# MYk8eJqI0nimOTJJfmXangNDsrX8np+3lXD0+6rCZisXRWIaeffyTMHZ31Qj1D50
# WYdRtX5yev4WgaXoKJQN3lkgXUcytvyHAgMBAAGjggFaMIIBVjAOBgNVHQ8BAf8E
# BAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAy
# BgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5j
# cmwwZgYIKwYBBQUHAQEEWjBYMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5zdGFy
# dHNzbC5jb20wMAYIKwYBBQUHMAKGJGh0dHA6Ly9haWEuc3RhcnRzc2wuY29tL2Nl
# cnRzL2NhLmNydDAdBgNVHQ4EFgQUPmKTmtfHGe4+j0kQhVUVIOOUhBwwHwYDVR0j
# BBgwFoAUTgvvGqRAW6UXaYcwyjRoQ9BBrvIwPwYDVR0gBDgwNjA0BgRVHSAAMCww
# KgYIKwYBBQUHAgEWHmh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeTANBgkq
# hkiG9w0BAQsFAAOCAgEAY6U81bNtJyjY67pTrzAL6kpdEtX5mspw+kxjjNdNVH5G
# 6lLnhaEkIxqdpvY/Wdw+UdNtExs+N8efKPSwh2m/BxXj2fSeLMwXcwHFookScEER
# 8ez0quCNzioqNHac7LCXPEnQzbtG2FHlePKNDWh8eU6KxiAzNzIrIxPthinHGgLT
# BOACHQM2YTlD8YoU5oN3dLmBOqtH0BDMZoLcjEIoEW1zC+TnVb3yU1G0xub6gnN7
# lP50vbAiHJYrnywQiXaloBV8B9YYfe6ZgvjqxwufwFcMVyE3UmCuDTsOpjqDEKpJ
# 25s+FUdkie5VqCS1aaudLo31X+9UvP45pfgyRqzyfUnVEhH4ZXxlBWZMzj2Xov5+
# m/+H3kxYuFA5xdqdshj/Zx00S7PkCSF+8M1NCcvFgQwjIw61bZAjDBl3P3a8xNTX
# sb2CjFdiNKbT3LD6IGeIf0b/EbPf0FXdvBrxm0ofMOhnngdPolPYCtoOGtZPAVe/
# xeu+/ZyKv6TSHlshaUO0iYfsmbXnZ51vvt/kkjwms9/qPFxSuE0fjEfF7aQazwRE
# Df2hiVPR0pAhvShtM3oU4XreEFEUWEYHs25fYV4WMmxkUKSgmSmwRq45tvtGH4LT
# b5+cd+iLqK8rBQL0E6xaUjjGfsYx7bueIvqTvCkrQvoxMbn/qDHCiypowDVq6TAw
# ggZqMIIFUqADAgECAhADAZoCOv9YsWvW1ermF/BmMA0GCSqGSIb3DQEBBQUAMGIx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0Et
# MTAeFw0xNDEwMjIwMDAwMDBaFw0yNDEwMjIwMDAwMDBaMEcxCzAJBgNVBAYTAlVT
# MREwDwYDVQQKEwhEaWdpQ2VydDElMCMGA1UEAxMcRGlnaUNlcnQgVGltZXN0YW1w
# IFJlc3BvbmRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNkXfx8
# s+CCNeDg9sYq5kl1O8xu4FOpnx9kWeZ8a39rjJ1V+JLjntVaY1sCSVDZg85vZu7d
# y4XpX6X51Id0iEQ7Gcnl9ZGfxhQ5rCTqqEsskYnMXij0ZLZQt/USs3OWCmejvmGf
# rvP9Enh1DqZbFP1FI46GRFV9GIYFjFWHeUhG98oOjafeTl/iqLYtWQJhiGFyGGi5
# uHzu5uc0LzF3gTAfuzYBje8n4/ea8EwxZI3j6/oZh6h+z+yMDDZbesF6uHjHyQYu
# RhDIjegEYNu8c3T6Ttj+qkDxss5wRoPp2kChWTrZFQlXmVYwk/PJYczQCMxr7GJC
# kawCwO+k8IkRj3cCAwEAAaOCAzUwggMxMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMB
# Af8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIBtjCCAbIw
# ggGhBglghkgBhv1sBwEwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdp
# Y2VydC5jb20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBl
# ACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBu
# AHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0
# AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0
# AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBl
# AG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5
# ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABl
# AHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG/WwD
# FTAfBgNVHSMEGDAWgBQVABIrE5iymQftHt+ivlcNK2cCzTAdBgNVHQ4EFgQUYVpN
# JLZJMp1KKnkag0v0HonByn0wfQYDVR0fBHYwdDA4oDagNIYyaHR0cDovL2NybDMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwOKA2oDSGMmh0
# dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENBLTEuY3Js
# MHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl
# cnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRBc3N1cmVkSURDQS0xLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAnSV+
# GzNNsiaBXJuGziMgD4CH5Yj//7HUaiwx7ToXGXEXzakbvFoWOQCd42yE5FpA+94G
# AYw3+puxnSR+/iCkV61bt5qwYCbqaVchXTQvH3Gwg5QZBWs1kBCge5fH9j/n4hFB
# pr1i2fAnPTgdKG86Ugnw7HBi02JLsOBzppLA044x2C/jbRcTBu7kA7YUq/OPQ6dx
# nSHdFMoVXZJB2vkPgdGZdA0mxA5/G7X1oPHGdwYoFenYk+VVFvC7Cqsc21xIJ2bI
# o4sKHOWV2q7ELlmgYd3a822iYemKC23sEhi991VUQAOSK2vCUcIKSK+w1G7g9BQK
# Ohvjjz3Kr2qNe9zYRDCCBs0wggW1oAMCAQICEAb9+QOWA63qAArrPye7uhswDQYJ
# KoZIhvcNAQEFBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu
# YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQg
# QXNzdXJlZCBJRCBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTIxMTExMDAwMDAw
# MFowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE
# CxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJ
# RCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IItmfnKwkKV
# pYBzQHDSnlZUXKnE0kEGj8kz/E1FkVyBn+0snPgWWd+etSQVwpi5tHdJ3InECtqv
# y15r7a2wcTHrzzpADEZNk+yLejYIA6sMNP4YSYL+x8cxSIB8HqIPkg5QycaH6zY/
# 2DDD/6b3+6LNb3Mj/qxWBZDwMiEWicZwiPkFl32jx0PdAug7Pe2xQaPtP77blUjE
# 7h6z8rwMK5nQxl0SQoHhg26Ccz8mSxSQrllmCsSNvtLOBq6thG9IhJtPQLnxTPKv
# mPv2zkBdXPao8S+v7Iki8msYZbHBc63X8djPHgp0XEK4aH631XcKJ1Z8D2KkPzIU
# YJX9BwSiCQIDAQABo4IDejCCA3YwDgYDVR0PAQH/BAQDAgGGMDsGA1UdJQQ0MDIG
# CCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcD
# CDCCAdIGA1UdIASCAckwggHFMIIBtAYKYIZIAYb9bAABBDCCAaQwOgYIKwYBBQUH
# AgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5o
# dG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0
# AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1
# AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABp
# AGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBl
# AGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBo
# AGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAg
# AGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAg
# AGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMBIGA1UdEwEB
# /wQIMAYBAf8CAQAweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8v
# b2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRp
# Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6
# MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy
# ZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwHQYDVR0OBBYEFBUAEisTmLKZB+0e
# 36K+Vw0rZwLNMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqG
# SIb3DQEBBQUAA4IBAQBGUD7Jtygkpzgdtlspr1LPUukxR6tWXHvVDQtBs+/sdR90
# OPKyXGGinJXDUOSCuSPRujqGcq04eKx1XRcXNHJHhZRW0eu7NoR3zCSl8wQZVann
# 4+erYs37iy2QwsDStZS9Xk+xBdIOPRqpFFumhjFiqKgz5Js5p8T1zh14dpQlc+Qq
# q8+cdkvtX8JLFuRLcEwAiR78xXm8TBJX/l/hHrwCXaj++wc4Tw3GXZG5D2dFzdaD
# 7eeSDY2xaYxP+1ngIw/Sqq4AfO6cQg7PkdcntxbuD8O9fAqg7iwIVYUiuOsYGk38
# KiGtSTGDR5V3cdyxG0tLHBCcdxTBnU8vWpUIKRAmMYIETzCCBEsCAQEwgYkwdTEL
# MAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKTAnBgNVBAsTIFN0
# YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSMwIQYDVQQDExpTdGFydENv
# bSBDbGFzcyAyIE9iamVjdCBDQQIQOb1CntKBbrrVvMkDtLpl5zANBglghkgBZQME
# AgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEM
# BgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqG
# SIb3DQEJBDEiBCBZo/F9DLNHJLaXKHlUQb8MfZ0TcjKnCQlv4yPH3IzYwjANBgkq
# hkiG9w0BAQEFAASCAQAOd4cDUFY06/7Wr5Ch9vfNC5nCAhH10LTysPJloM3vAUxy
# rc212Kz+bCVaY4QBZhJy1+R5tAjWgsAjqB5a3kOXntQ50XwWFeLdxbI9H4eCGIeh
# uSNfC5grYPPaLojVaEUDgGMvRPWrXjqmTYOzl/qgr7KDqQ95tq0fHbDcYyesh9oc
# TNYLKCdLDHqF46/gHIuKiH1lf900MiHNrgm3qlbP4hAdVQ8riCcXbGpjSxvV4bQp
# 54XNi0mEKFqQOzB0aye46dhVRhmLrhhj9bvI//ppDKp5BDoal9QW3riioaNJtflC
# BNiXrwVF+XOujgSVv/MDjOzA5BzSEDBH3Uq8dP0KoYICDzCCAgsGCSqGSIb3DQEJ
# BjGCAfwwggH4AgEBMHYwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0
# IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNl
# cnQgQXNzdXJlZCBJRCBDQS0xAhADAZoCOv9YsWvW1ermF/BmMAkGBSsOAwIaBQCg
# XTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xODAx
# MzAwNjE1NTlaMCMGCSqGSIb3DQEJBDEWBBSArCkPHqTJO7TCfx1nrnmlFYtctzAN
# BgkqhkiG9w0BAQEFAASCAQAKfeoyeIuJ27I++71kH9eKrMz+B0z/eAMJd8GLcKuM
# XmsmEhORXp4hzCu2QUWzUpmaFg9gC157CsXFeCu3gz/pCGjpWFcZCMhJvE+dq0Aj
# y6nZhWfS+GIK73bce2QDUDKVp2pX7KS3oRE0kRJFD0v+PKZxxb+qpE/7UuH0+Wij
# JQBIGpey4oKodMhUJEWIEgwXUw7hduYH6XmMVhOibn/Qrn6Lt4tvuEtaBQ/Gp09N
# rpDBholC9GZk0zKBjnyqtawgMkqK118bDuRZN9lLw9XkTa6/cWbk723ksA3lhw3l
# DRGoYPa909eqNkrZ2BuU2bM41qnN4j3loCfDKU7xONg9
# SIG # End signature block