# This powershell script is part of WVDAdmin and Project Hydra - see https://blog.itprocloud.de/Windows-Virtual-Desktop-Admin/ for more information # Current Version of this script: 4.7 param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [ValidateSet('Generalize','JoinDomain','DataPartition','RDAgentBootloader','RestartBootloader','StartBootloader','CleanFirstStart', 'RenameComputer')] [string] $Mode, [string] $StrongGeneralize='0', [string] $ComputerNewname='', #Only for SecureBoot process (workaround, normaly not used) [string] $LocalAdminName='localAdmin', #Only for SecureBoot process (workaround, normaly not used) [string] $LocalAdminPassword='', [string] $DomainJoinUserName='', [string] $DomainJoinUserPassword='', [string] $LocalAdminName64='bG9jYWxBZG1pbg==', #Base64-coding is used if not empty - providing the older parameters to be compatible [string] $LocalAdminPassword64='', [string] $DomainJoinUserName64='', [string] $DomainJoinUserPassword64='', [string] $DomainJoinOU='', [string] $AadOnly='0', [string] $JoinMem='0', [string] $MovePagefileToC='0', [string] $DomainFqdn='', [string] $WvdRegistrationKey='', [string] $LogDir="$env:windir\system32\logfiles", [string] $HydraAgentUri='', #Only used by Hydra [string] $HydraAgentSecret='', #Only used by Hydra [string] $DownloadNewestAgent='0' #Download the newes agent, event if a local agent exist ) function LogWriter($message) { $message="$(Get-Date ([datetime]::UtcNow) -Format "o") $message" write-host($message) if ([System.IO.Directory]::Exists($LogDir)) {try {write-output($message) | Out-File $LogFile -Append} catch {}} } function ShowDrives() { $drives = Get-WmiObject -Class win32_volume -Filter "DriveType = 3" LogWriter("Drives:") foreach ($drive in $drives) { LogWriter("Name: '$($drive.Name)', Letter: '$($drive.DriveLetter)', Label: '$($drive.Label)'") } } function ShowPageFiles() { $pageFiles = Get-WmiObject -Class Win32_PageFileSetting LogWriter("Pagefiles:") foreach ($pageFile in $pageFiles) { LogWriter("Name: '$($pageFile.Name)', Maximum size: '$($pageFile.MaximumSize)'") } } function RedirectPageFileToC() { $CurrentPageFile = Get-WmiObject -Query 'select * from Win32_PageFileSetting' LogWriter("Pagefile name: '$($CurrentPageFile.Name)', max size: $($CurrentPageFile.MaximumSize)") $CurrentPageFile.delete() LogWriter("Pagefile deleted") $CurrentPageFile = Get-WmiObject -Query 'select * from Win32_PageFileSetting' if ($null -eq $CurrentPageFile) { LogWriter("Pagefile deletion successful") } else { LogWriter("Pagefile deletion failed") } Set-WMIInstance -Class Win32_PageFileSetting -Arguments @{name='c:\pagefile.sys';InitialSize = 0; MaximumSize = 0} $CurrentPageFile = Get-WmiObject -Query 'select * from Win32_PageFileSetting' if ($null -eq $CurrentPageFile) { LogWriter("Pagefile not found") } else { LogWriter("New pagefile name: '$($CurrentPageFile.Name)', max size: $($CurrentPageFile.MaximumSize)") } } function UnzipFile ($zipfile, $outdir) { # Based on https://gist.github.com/nachivpn/3e53dd36120877d70aee Add-Type -AssemblyName System.IO.Compression.FileSystem $files = [System.IO.Compression.ZipFile]::OpenRead($zipfile) foreach ($entry in $files.Entries) { $targetPath = [System.IO.Path]::Combine($outdir, $entry.FullName) $directory = [System.IO.Path]::GetDirectoryName($targetPath) if(!(Test-Path $directory )){ New-Item -ItemType Directory -Path $directory | Out-Null } if(!$targetPath.EndsWith("/")){ [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $targetPath, $true); } } } function DownloadFile ( $url, $outFile) { $i=3 $ok=$false; do { try { LogWriter("Try to download file") Invoke-WebRequest -Uri $url -OutFile $outFile -UseBasicParsing $ok=$true } catch { $i--; if ($i -le 0) { throw } LogWriter("Re-trying download after 10 seconds") Start-Sleep -Seconds 10 } } while (!$ok) } # Define static variables $LocalConfig="C:\ITPC-WVD-PostCustomizing" $unattend="PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnPz48dW5hdHRlbmQgeG1sbnM9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206dW5hdHRlbmQiPjxzZXR0aW5ncyBwYXNzPSJvb2JlU3lzdGVtIj48Y29tcG9uZW50IG5hbWU9Ik1pY3Jvc29mdC1XaW5kb3dzLVNoZWxsLVNldHVwIiBwcm9jZXNzb3JBcmNoaXRlY3R1cmU9ImFtZDY0IiBwdWJsaWNLZXlUb2tlbj0iMzFiZjM4NTZhZDM2NGUzNSIgbGFuZ3VhZ2U9Im5ldXRyYWwiIHZlcnNpb25TY29wZT0ibm9uU3hTIiB4bWxuczp3Y209Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vV01JQ29uZmlnLzIwMDIvU3RhdGUiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiPjxPT0JFPjxTa2lwTWFjaGluZU9PQkU+dHJ1ZTwvU2tpcE1hY2hpbmVPT0JFPjxTa2lwVXNlck9PQkU+dHJ1ZTwvU2tpcFVzZXJPT0JFPjwvT09CRT48L2NvbXBvbmVudD48L3NldHRpbmdzPjwvdW5hdHRlbmQ+" # Define logfile $LogFile=$LogDir+"\AVD.Customizing.log" # Main LogWriter("Starting ITPC-WVD-Image-Processing in mode ${Mode}") # Generating variables from Base64-coding if ($LocalAdminName64) {$LocalAdminName=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($LocalAdminName64))} if ($LocalAdminPassword64) {$LocalAdminPassword=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($LocalAdminPassword64))} if ($DomainJoinUserName64) {$DomainJoinUserName=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($DomainJoinUserName64))} if ($DomainJoinUserPassword64) {$DomainJoinUserPassword=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($DomainJoinUserPassword64))} # check for the existend of the helper scripts if ((Test-Path ($LocalConfig+"\ITPC-WVD-Image-Processing.ps1")) -eq $false) { # Create local directory for script(s) and copy files (including the RD agent and boot loader - rename it to the specified name) LogWriter("Copy files to local session host or downloading files from Microsoft") new-item $LocalConfig -ItemType Directory -ErrorAction Ignore try {(Get-Item $LocalConfig -ErrorAction Ignore).attributes="Hidden"} catch {} if ((Test-Path ("${PSScriptRoot}\ITPC-WVD-Image-Processing.ps1")) -eq $false) { LogWriter("Creating ITPC-WVD-Image-Processing.ps1") Copy-Item "$($MyInvocation.InvocationName)" -Destination ($LocalConfig+"\ITPC-WVD-Image-Processing.ps1") } else {Copy-Item "${PSScriptRoot}\ITPC-WVD-Image-Processing.ps1" -Destination ($LocalConfig+"\")} } if ($ComputerNewname -eq "" -or $DownloadNewestAgent -eq "1") { if ((Test-Path ($LocalConfig+"\Microsoft.RDInfra.RDAgent.msi")) -eq $false -or $DownloadNewestAgent -eq "1") { if ((Test-Path ($ScriptRoot+"\Microsoft.RDInfra.RDAgent.msi")) -eq $false -or $DownloadNewestAgent -eq "1") { LogWriter("Downloading RDAgent") DownloadFile "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RWrmXv" ($LocalConfig+"\Microsoft.RDInfra.RDAgent.msi") #Invoke-WebRequest -Uri "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RWrmXv" -OutFile ($LocalConfig+"\Microsoft.RDInfra.RDAgent.msi") } else {Copy-Item "${PSScriptRoot}\Microsoft.RDInfra.RDAgent.msi" -Destination ($LocalConfig+"\")} } if ((Test-Path ($LocalConfig+"\Microsoft.RDInfra.RDAgentBootLoader.msi")) -eq $false -or $DownloadNewestAgent -eq "1") { if ((Test-Path ($ScriptRoot+"\Microsoft.RDInfra.RDAgentBootLoader.msi ")) -eq $false -or $DownloadNewestAgent -eq "1") { LogWriter("Downloading RDBootloader") DownloadFile "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RWrxrH" ($LocalConfig+"\Microsoft.RDInfra.RDAgentBootLoader.msi") #Invoke-WebRequest -Uri "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RWrxrH" -OutFile ($LocalConfig+"\Microsoft.RDInfra.RDAgentBootLoader.msi") } else {Copy-Item "${PSScriptRoot}\Microsoft.RDInfra.RDAgentBootLoader.msi" -Destination ($LocalConfig+"\")} } } # updating local script (from maybe an older version from the last image process) Copy-Item "$($MyInvocation.InvocationName)" -Destination ($LocalConfig+"\ITPC-WVD-Image-Processing.ps1") -Force -ErrorAction SilentlyContinue # check, if secure boot is enabled (used by the snapshot workaround) $isSecureBoot=$false try { $isSecureBoot=Confirm-SecureBootUEFI } catch {} # Start script by mode if ($mode -eq "Generalize") { LogWriter("Removing existing Remote Desktop Agent Boot Loader") Uninstall-Package -Name "Remote Desktop Agent Boot Loader" -AllVersions -Force -ErrorAction SilentlyContinue LogWriter("Removing existing Remote Desktop Services Infrastructure Agent") Uninstall-Package -Name "Remote Desktop Services Infrastructure Agent" -AllVersions -Force -ErrorAction SilentlyContinue Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\RDMonitoringAgent" -Force -ErrorAction Ignore LogWriter("Disabling ITPC-LogAnalyticAgent and MySmartScale if exist") Disable-ScheduledTask -TaskName "ITPC-LogAnalyticAgent for RDS and Citrix" -ErrorAction Ignore Disable-ScheduledTask -TaskName "ITPC-MySmartScaleAgent" -ErrorAction Ignore LogWriter("Cleaning up reliability messages") $key="HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability" Remove-ItemProperty -Path $key -Name "DirtyShutdown" -ErrorAction Ignore Remove-ItemProperty -Path $key -Name "DirtyShutdownTime" -ErrorAction Ignore Remove-ItemProperty -Path $key -Name "LastAliveStamp" -ErrorAction Ignore Remove-ItemProperty -Path $key -Name "TimeStampInterval" -ErrorAction Ignore # Triggering dotnet to execute queued items $dotnetRoot="$env:windir\Microsoft.NET\Framework" Get-ChildItem -Path $dotnetRoot -Directory | foreach { if (Test-Path "$($_.FullName)\ngen.exe") { LogWriter("Triggering dotnet to execute queued items in: $($_.FullName)") Start-Process -FilePath "$($_.FullName)\ngen.exe" -Wait -ArgumentList "ExecuteQueuedItems" -ErrorAction SilentlyContinue } } # Read property from registry (force imaging, like dism) $force=$StrongGeneralize -eq "1" if (Test-Path -Path "HKLM:\SOFTWARE\ITProCloud\WVD.Force") { $force=$true } # DISM cleanup if ($force -and (Test-Path "$env:windir\system32\Dism.exe")) { LogWriter("DISM cleanup") Start-Process -FilePath "$env:windir\system32\Dism.exe" -Wait -ArgumentList "/online /cleanup-image /startcomponentcleanup /resetbase" -ErrorAction SilentlyContinue } LogWriter("Modifying sysprep to avoid issues with AppXPackages - Start") $sysPrepActionPath="$env:windir\System32\Sysprep\ActionFiles" $sysPrepActionFile="Generalize.xml" $sysPrepActionPathItem = Get-Item $sysPrepActionPath.Replace("C:\","\\localhost\\c$\") -ErrorAction Ignore $acl = $sysPrepActionPathItem.GetAccessControl() $acl.SetOwner((New-Object System.Security.Principal.NTAccount("SYSTEM"))) $sysPrepActionPathItem.SetAccessControl($acl) $aclSystemFull = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM","FullControl","Allow") $acl.AddAccessRule($aclSystemFull) $sysPrepActionPathItem.SetAccessControl($acl) [xml]$xml = Get-Content -Path "$sysPrepActionPath\$sysPrepActionFile" $xmlNode=$xml.sysprepInformation.imaging | where {$_.sysprepModule.moduleName -match "AppxSysprep.dll"} if ($xmlNode -ne $null) { $xmlNode.ParentNode.RemoveChild($xmlNode) $xml.sysprepInformation.imaging.Count $xml.Save("$sysPrepActionPath\$sysPrepActionFile.new") Remove-Item "$sysPrepActionPath\$sysPrepActionFile.old" -Force -ErrorAction Ignore Move-Item "$sysPrepActionPath\$sysPrepActionFile" "$sysPrepActionPath\$sysPrepActionFile.old" Move-Item "$sysPrepActionPath\$sysPrepActionFile.new" "$sysPrepActionPath\$sysPrepActionFile" LogWriter("Modifying sysprep to avoid issues with AppXPackages - Done") } # Preparation for the snapshot workaround if ($isSecureBoot -and $LocalAdminName -ne "" -and $LocalAdminPassword -ne "") { LogWriter("Creating administrator $LocalAdminName") New-LocalUser "$LocalAdminName" -Password (ConvertTo-SecureString $LocalAdminPassword -AsPlainText -Force) -FullName "$LocalAdminName" -Description "Local Administrator" -ErrorAction SilentlyContinue Add-LocalGroupMember -Group "Administrators" -Member "$LocalAdminName" -ErrorAction SilentlyContinue } LogWriter("Removing an older Sysprep state") Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\Sysprep" -Name "SysprepCorrupt" -ErrorAction Ignore New-ItemProperty -Path "HKLM:\SYSTEM\Setup\Status\SysprepStatus" -Name "State" -Value 2 -force New-ItemProperty -Path "HKLM:\SYSTEM\Setup\Status\SysprepStatus" -Name "GeneralizationState" -Value 7 -force New-Item -Path "HKLM:\Software\Microsoft\DesiredStateConfiguration" -ErrorAction Ignore New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\DesiredStateConfiguration" -Name "AgentId" -Value "" -force -ErrorAction Ignore LogWriter("Saving time zone info for re-deploy") $timeZone=(Get-TimeZone).Id LogWriter("Current time zone is: "+$timeZone) New-Item -Path "HKLM:\SOFTWARE" -Name "ITProCloud" -ErrorAction Ignore New-Item -Path "HKLM:\SOFTWARE\ITProCloud" -Name "WVD.Runtime" -ErrorAction Ignore New-ItemProperty -Path "HKLM:\SOFTWARE\ITProCloud\WVD.Runtime" -Name "TimeZone.Origin" -Value $timeZone -force LogWriter("Removing existing Azure Monitoring Certificates") Get-ChildItem "Cert:\LocalMachine\Microsoft Monitoring Agent" -ErrorAction Ignore | Remove-Item # Check, if the optimization script exist (Hydra: use a script inside Hydra) if ([System.IO.File]::Exists("C:\ProgramData\Optimize\Win10_VirtualDesktop_Optimize.ps1")) { LogWriter("Running VDI Optimization script") Start-Process -wait -FilePath PowerShell.exe -WorkingDirectory "C:\ProgramData\Optimize" -ArgumentList '-ExecutionPolicy Bypass -File "C:\ProgramData\Optimize\Win10_VirtualDesktop_Optimize.ps1 -AcceptEULA -Optimizations WindowsMediaPlayer,AppxPackages,ScheduledTasks,DefaultUserSettings,Autologgers,Services,NetworkOptimizations"' -RedirectStandardOutput "$($LogDir)\VirtualDesktop_Optimize.Stage1.Out.txt" -RedirectStandardError "$($LogDir)\VirtualDesktop_Optimize.Stage1.Warning.txt" } # prepare cleanup task for new deployed VMs - solve an issue with the runcommand api giving older log data LogWriter("Preparing CleanFirstStart task") $action = New-ScheduledTaskAction -Execute "$env:windir\System32\WindowsPowerShell\v1.0\Powershell.exe" -Argument "-executionPolicy Unrestricted -File `"$LocalConfig\ITPC-WVD-Image-Processing.ps1`" -Mode `"CleanFirstStart`"" $trigger = New-ScheduledTaskTrigger -AtStartup $principal = New-ScheduledTaskPrincipal 'NT Authority\SYSTEM' -RunLevel Highest $settingsSet = New-ScheduledTaskSettingsSet $task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger -Settings $settingsSet Register-ScheduledTask -TaskName 'ITPC-AVD-CleanFirstStart-Helper' -InputObject $task -ErrorAction Ignore Enable-ScheduledTask -TaskName 'ITPC-AVD-CleanFirstStart-Helper' LogWriter("Added new startup task to run the CleanFirstStart") # check if D:-drive not the temporary storage and having three drives $modifyDrives=$false $disks=Get-WmiObject -Class win32_volume | Where-Object { $_.DriveLetter -ne $null -and $_.DriveType -eq 3 } foreach ($disk in $disks) {if ($disk.Name -ne 'D:\' -and $disk.Label -eq 'Temporary Storage') {$modifyDrives=$true}} if ($disks.Count -eq 3 -and $modifyDrives) { LogWriter("VM with 3 drives so prepare change of drive letters of temp and data after deployment") New-ItemProperty -Path "HKLM:\SOFTWARE\ITProCloud\WVD.Runtime" -Name "ChangeDrives" -Value 1 -force # check if default value 'automatic manage pagefile size for all devices' is activated if ($null -eq (Get-WmiObject Win32_Pagefile) ) { # disable 'automatic manage pagefile size for all devices' $sys = Get-WmiObject Win32_Computersystem -EnableAllPrivileges $sys.AutomaticManagedPagefile = $false $sys.put() LogWriter("Automatic manage pagefile size for all devices deactivated") } else { LogWriter("Automatic manage pagefile size for all devices not activated") } # redirect pagefile to C: to rename data partition after deployment RedirectPageFileToC } LogWriter("Starting sysprep to generalize session host") if ([System.Environment]::OSVersion.Version.Major -le 6) { #Windows 7 LogWriter("Enabling RDP8 on Windows 7") New-Item -Path "HKLM:\SOFTWARE" -Name "Policies" -ErrorAction Ignore New-Item -Path "HKLM:\SOFTWARE\Policies" -Name "Microsoft" -ErrorAction Ignore New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft" -Name "Windows NT" -ErrorAction Ignore New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT" -Name "Terminal Services" -ErrorAction Ignore New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" -Name "fServerEnableRDP8" -Value 1 -force Start-Process -FilePath "$env:windir\System32\Sysprep\sysprep" -ArgumentList "/generalize /oobe /shutdown" } else { if ($isSecureBoot) { LogWriter("Secure boot is enabled") write-output([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($unattend))) | Out-File "$LocalConfig\unattend.xml" -Encoding ASCII write-output([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($unattend))) | Out-File "$env:windir\panther\unattend.xml" -Encoding ASCII Start-Process -FilePath "$env:windir\System32\Sysprep\sysprep" -ArgumentList "/generalize /oobe /shutdown /mode:vm /unattend:$LocalConfig\unattend.xml" } else { Start-Process -FilePath "$env:windir\System32\Sysprep\sysprep" -ArgumentList "/generalize /oobe /shutdown /mode:vm" } } } elseif ($mode -eq "RenameComputer") { # Used for the snapshot workaround LogWriter("Renaming computer to: "+$readComputerNewname) Rename-Computer -NewName $ComputerNewname -Force -ErrorAction SilentlyContinue } elseif ($mode -eq "JoinDomain") { # Removing existing agent if exist LogWriter("Removing existing Remote Desktop Agent Boot Loader") Uninstall-Package -Name "Remote Desktop Agent Boot Loader" -AllVersions -Force -ErrorAction SilentlyContinue LogWriter("Removing existing Remote Desktop Services Infrastructure Agent") Uninstall-Package -Name "Remote Desktop Services Infrastructure Agent" -AllVersions -Force -ErrorAction SilentlyContinue Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\RDMonitoringAgent" -Force -ErrorAction Ignore # Storing AadOnly to registry LogWriter("Storing AadOnly to registry: "+$AadOnly) New-Item -Path "HKLM:\SOFTWARE" -Name "ITProCloud" -ErrorAction Ignore New-Item -Path "HKLM:\SOFTWARE\ITProCloud" -Name "WVD.Runtime" -ErrorAction Ignore New-ItemProperty -Path "HKLM:\SOFTWARE\ITProCloud\WVD.Runtime" -Name "AadOnly" -Value $AadOnly -force # Checking for a saved time zone information if (Test-Path -Path "HKLM:\SOFTWARE\ITProCloud\WVD.Runtime") { $timeZone=(Get-ItemProperty -Path "HKLM:\SOFTWARE\ITProCloud\WVD.Runtime" -ErrorAction Ignore)."TimeZone.Origin" if ($timeZone -ne "" -and $timeZone -ne $null) { LogWriter("Setting time zone to: "+$timeZone) Set-TimeZone -Id $timeZone } } # AD / AAD handling LogWriter("Cleaning up previous AADLoginExtension / AAD join") Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows Azure\CurrentVersion\AADLoginForWindowsExtension" -Force -ErrorAction Ignore if (Test-Path -Path "$($env:WinDir)\system32\Dsregcmd.exe") { Start-Process -wait -FilePath "$($env:WinDir)\system32\Dsregcmd.exe" -ArgumentList "/leave" -ErrorAction SilentlyContinue } if ($DomainJoinUserName -ne "" -and $AadOnly -ne "1") { LogWriter("Joining AD domain") $psc = New-Object System.Management.Automation.PSCredential($DomainJoinUserName, (ConvertTo-SecureString $DomainJoinUserPassword -AsPlainText -Force)) $retry=3 $ok=$false do{ try { if ($DomainJoinOU -eq "") { Add-Computer -DomainName $DomainFqdn -Credential $psc -Force -ErrorAction Stop $ok=$true LogWriter("Domain joined successfully") } else { Add-Computer -DomainName $DomainFqdn -OUPath $DomainJoinOU -Credential $psc -Force -ErrorAction Stop $ok=$true LogWriter("Domain joined successfully") } } catch { if ($retry -eq 0) {throw $_} $retry-- LogWriter("Retry domain join because of an error: $_") Start-Sleep -Seconds 10 } } while($ok -ne $true) } else { LogWriter("AAD only is selected. Skipping joining to a native AD, joining AAD") $aadPath=@(Get-ChildItem -Directory "C:\Packages\Plugins\Microsoft.Azure.ActiveDirectory.AADLoginForWindows")[@(Get-ChildItem -Directory "C:\Packages\Plugins\Microsoft.Azure.ActiveDirectory.AADLoginForWindows").count-1].fullname Start-Process -wait -FilePath "$aadPath\AADLoginForWindowsHandler.exe" -WorkingDirectory $aadPath -ArgumentList 'enable' -RedirectStandardOutput "$($LogDir)\Avd.AadJoin.Out.txt" -RedirectStandardError "$($LogDir)\Avd.AadJoin.Warning.txt" if ($JoinMem -eq "1") { LogWriter("Joining Microsoft Endpoint Manamgement is selected. Try to register to MEM") Start-Process -wait -FilePath "$($env:WinDir)\system32\Dsregcmd.exe" -ArgumentList "/AzureSecureVMJoin /debug /MdmId 0000000a-0000-0000-c000-000000000000" -RedirectStandardOutput "$($LogDir)\Avd.MemJoin.Out.txt" -RedirectStandardError "$($LogDir)\Avd.MemJoin.Warning.txt" } try { if ($AadOnly) { $timeOut=(Get-Date).AddSeconds(5*60) do { LogWriter("Waiting for the domain join") Start-Sleep -Seconds 3#AzureAdJoined : YES } while ((Get-Date) -le $timeOut -and (Select-String -InputObject (&dsregcmd /status) -pattern "AzureAdJoined : YES").length -eq 0) } } catch {} } # check for disk handling $modifyDrives=$false if (Test-Path -Path "HKLM:\SOFTWARE\ITProCloud\WVD.Runtime") { if ((Get-ItemProperty -Path "HKLM:\SOFTWARE\ITProCloud\WVD.Runtime").ChangeDrives -eq 1) { $disks=Get-WmiObject -Class win32_volume | Where-Object { $_.DriveLetter -ne $null -and $_.DriveType -eq 3 } foreach ($disk in $disks) {if ($disk.Name -eq 'D:\' -and $disk.Label -eq 'Temporary Storage') {$modifyDrives=$true}} if ($modifyDrives -and $disks.Count -eq 3) { # change drive letters of temp and data drive for VMs with 3 drives LogWriter("VM with 3 drives so delete old pagefile and install runonce key") # create scheduled task executed at startup for next phase $action = New-ScheduledTaskAction -Execute "$env:windir\System32\WindowsPowerShell\v1.0\Powershell.exe" -Argument "-executionPolicy Unrestricted -File `"$LocalConfig\ITPC-WVD-Image-Processing.ps1`" -Mode `"DataPartition`"" $trigger = New-ScheduledTaskTrigger -AtStartup $principal = New-ScheduledTaskPrincipal 'NT Authority\SYSTEM' -RunLevel Highest $settingsSet = New-ScheduledTaskSettingsSet $task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger -Settings $settingsSet Register-ScheduledTask -TaskName 'ITPC-AVD-Disk-Mover-Helper' -InputObject $task -ErrorAction Ignore Enable-ScheduledTask -TaskName 'ITPC-AVD-Disk-Mover-Helper' LogWriter("Added new startup task for the disk handling") # change c:\pagefile.sys to e:\pagefile.sys ShowPageFiles $CurrentPageFile = Get-WmiObject -Query 'select * from Win32_PageFileSetting' if ($null -eq $CurrentPageFile) { LogWriter("No pagefile found") } else { if ($CurrentPageFile.Name.tolower().contains('d:')) { $CurrentPageFile.delete() LogWriter("Old pagefile deleted") Set-WMIInstance -Class Win32_PageFileSetting -Arguments @{name='c:\pagefile.sys';InitialSize = 0; MaximumSize = 0} LogWriter("Set pagefile to c:\pagefile.sys") ShowPageFiles } } ShowPageFiles } } } # check to move pagefile finally to C if ($MovePagefileToC -eq "1") { RedirectPageFileToC } # install Hydra Agent (Hydra only) if ($HydraAgentUri -ne "") { $uri=$HydraAgentUri $secret=$HydraAgentSecret $DownloadAdress="https://$($uri)/Download/HydraAgent" try { if ((Test-Path ("$env:ProgramFiles\ITProCloud.de")) -eq $false) { new-item "$env:ProgramFiles\ITProCloud.de" -ItemType Directory -ErrorAction Ignore } if ((Test-Path ("$env:ProgramFiles\ITProCloud.de\HydraAgent")) -eq $false) { new-item "$env:ProgramFiles\ITProCloud.de\HydraAgent" -ItemType Directory -ErrorAction Ignore } Remove-Item -Path "$env:ProgramFiles\ITProCloud.de\HydraAgent\HydraAgent.zip" -Force -ErrorAction Ignore LogWriter("Downloading HydraAgent.zip from $DownloadAdress") DownloadFile $DownloadAdress "$env:ProgramFiles\ITProCloud.de\HydraAgent\HydraAgent.zip" #Invoke-WebRequest -Uri $DownloadAdress -OutFile "$env:ProgramFiles\ITProCloud.de\HydraAgent\HydraAgent.zip" -UseBasicParsing # Stop a running instance LogWriter("Stop a running instance") Stop-ScheduledTask -TaskName 'ITPC-AVD-Hydra-Helper' -ErrorAction Ignore Stop-Process -Name HydraAgent -Force -ErrorAction Ignore Start-Sleep -Seconds 6 UnzipFile "$env:ProgramFiles\ITProCloud.de\HydraAgent\HydraAgent.zip" "$env:ProgramFiles\ITProCloud.de\HydraAgent" # Configuring the agent LogWriter("Configuring the agent") cd "$env:ProgramFiles\ITProCloud.de\HydraAgent" . "$env:ProgramFiles\ITProCloud.de\HydraAgent\HydraAgent.exe" -i -u "wss://$($uri)/wsx" -s $secret } catch { LogWriter("An error occurred while installing Hydra Agent: $_") } } # install AVD Agent if a registration key given if ($WvdRegistrationKey -ne "") { if ([System.Environment]::OSVersion.Version.Major -gt 6) { LogWriter("Installing AVD agent") Start-Process -wait -FilePath "${LocalConfig}\Microsoft.RDInfra.RDAgent.msi" -ArgumentList "/quiet /qn /norestart /passive RegistrationToken=${WvdRegistrationKey}" if ($false) { LogWriter("Installing AVD boot loader - current path is ${LocalConfig}") Start-Process -wait -FilePath "${LocalConfig}\Microsoft.RDInfra.RDAgentBootLoader.msi" -ArgumentList "/quiet /qn /norestart /passive" LogWriter("Waiting for the service RDAgentBootLoader") $bootloaderServiceName = "RDAgentBootLoader" $retryCount = 0 while ( -not (Get-Service "RDAgentBootLoader" -ErrorAction SilentlyContinue)) { $retry = ($retryCount -lt 6) LogWriter("Service RDAgentBootLoader was not found") if ($retry) { LogWriter("Retrying again in 30 seconds, this will be retry $retryCount") } else { LogWriter("Retry limit exceeded" ) throw "RDAgentBootLoader didn't become available after 6 retries" } $retryCount++ Start-Sleep -Seconds 30 } } else { LogWriter("Preparing AVD boot loader task") $action = New-ScheduledTaskAction -Execute "$env:windir\System32\WindowsPowerShell\v1.0\Powershell.exe" -Argument "-executionPolicy Unrestricted -File `"$LocalConfig\ITPC-WVD-Image-Processing.ps1`" -Mode `"RDAgentBootloader`"" $trigger = New-ScheduledTaskTrigger -AtStartup $principal = New-ScheduledTaskPrincipal 'NT Authority\SYSTEM' -RunLevel Highest $settingsSet = New-ScheduledTaskSettingsSet $task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger -Settings $settingsSet Register-ScheduledTask -TaskName 'ITPC-AVD-RDAgentBootloader-Helper' -InputObject $task -ErrorAction Ignore Enable-ScheduledTask -TaskName 'ITPC-AVD-RDAgentBootloader-Helper' LogWriter("Added new startup task to run the RDAgentBootloader") $class = cimclass MSFT_TaskEventTrigger root/Microsoft/Windows/TaskScheduler $triggerM = $class | New-CimInstance -ClientOnly $triggerM.Enabled = $true $triggerM.Subscription='' $actionM = New-ScheduledTaskAction -Execute "$env:windir\System32\WindowsPowerShell\v1.0\Powershell.exe" -Argument "-executionPolicy Unrestricted -File `"$LocalConfig\ITPC-WVD-Image-Processing.ps1`" -Mode `"RestartBootloader`"" $settingsM = New-ScheduledTaskSettingsSet $taskM = New-ScheduledTask -Action $actionM -Principal $principal -Trigger $triggerM -Settings $settingsM -Description "Restarts the bootloader in case of an known issue (timeout, download error) while installing the RDagent" Register-ScheduledTask -TaskName 'ITPC-AVD-RDAgentBootloader-Monitor-1' -InputObject $taskM -ErrorAction Ignore Enable-ScheduledTask -TaskName 'ITPC-AVD-RDAgentBootloader-Monitor-1' -ErrorAction Ignore LogWriter("Added new task to monitor the RDAgentBootloader") } } else { if ((Test-Path "${LocalConfig}\Microsoft.RDInfra.WVDAgent.msi") -eq $false) { LogWriter("Downloading Microsoft.RDInfra.WVDAgent.msi") DownloadFile "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE3JZCm" "${LocalConfig}\Microsoft.RDInfra.WVDAgent.msi" #Invoke-WebRequest -Uri 'https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE3JZCm' -OutFile "${LocalConfig}\Microsoft.RDInfra.WVDAgent.msi" -UseBasicParsing } if ((Test-Path "${LocalConfig}\Microsoft.RDInfra.WVDAgentManager.msi") -eq $false) { LogWriter("Downloading Microsoft.RDInfra.WVDAgentManager.msi") DownloadFile "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE3K2e3" "${LocalConfig}\Microsoft.RDInfra.WVDAgentManager.msi" #nvoke-WebRequest -Uri 'https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE3K2e3' -OutFile "${LocalConfig}\Microsoft.RDInfra.WVDAgentManager.msi" -UseBasicParsing } LogWriter("Installing AVDAgent") Start-Process -wait -FilePath "${LocalConfig}\Microsoft.RDInfra.WVDAgent.msi" -ArgumentList "/q RegistrationToken=${WvdRegistrationKey}" LogWriter("Installing AVDAgentManager") Start-Process -wait -FilePath "${LocalConfig}\Microsoft.RDInfra.WVDAgentManager.msi" -ArgumentList '/q' } } LogWriter("Enabling ITPC-LogAnalyticAgent and MySmartScale if exist") Enable-ScheduledTask -TaskName "ITPC-LogAnalyticAgent for RDS and Citrix" -ErrorAction Ignore Enable-ScheduledTask -TaskName "ITPC-MySmartScaleAgent" -ErrorAction Ignore if ([System.IO.File]::Exists("C:\ProgramData\Optimize\Win10_VirtualDesktop_Optimize.ps1")) { LogWriter("Running VDI Optimization script") Start-Process -wait -FilePath PowerShell.exe -WorkingDirectory "C:\ProgramData\Optimize" -ArgumentList '-ExecutionPolicy Bypass -File "C:\ProgramData\Optimize\Win10_VirtualDesktop_Optimize.ps1 -AcceptEULA -Optimizations WindowsMediaPlayer,AppxPackages,ScheduledTasks,DefaultUserSettings,Autologgers,Services,NetworkOptimizations"' -RedirectStandardOutput "$($LogDir)\VirtualDesktop_Optimize.Stage2.Out.txt" -RedirectStandardError "$($LogDir)\VirtualDesktop_Optimize.Stage2.Warning.txt" } # Final reboot LogWriter("Finally restarting session host") Restart-Computer -Force -ErrorAction SilentlyContinue } elseif ($Mode -eq "DataPartition") { if ((Get-WmiObject -Class win32_volume | Where-Object { $_.DriveLetter -ne $null -and $_.DriveType -eq 3 }).Count -eq 3) { # change drive letters of temp and data drive for VMs with 3 drives LogWriter("VM with 3 drives so change drive letters of temp and data") ShowDrives # change c:\pagefile.sys to e:\pagefile.sys ShowPageFiles $CurrentPageFile = Get-WmiObject -Query 'select * from Win32_PageFileSetting' if ($null -eq $CurrentPageFile) { LogWriter("No pagefile found") } else { if ($CurrentPageFile.Name.tolower().contains('c:')) { ShowDrives # change temp drive to Z: $drive = Get-WmiObject -Class win32_volume -Filter "DriveLetter = 'd:'" if ($null -ne $drive) { LogWriter("d: drive: $($drive.Label)") Set-WmiInstance -input $drive -Arguments @{ DriveLetter='z:' } LogWriter("changed drive letter to z:") ShowDrives } else { LogWriter("Drive D: not found") } # change data drive to D: $drive = Get-WmiObject -Class win32_volume -Filter "DriveLetter = 'e:'" if ($null -ne $drive) { LogWriter("e: drive: $($drive.Label)") Set-WmiInstance -input $drive -Arguments @{ DriveLetter='D:' } LogWriter("changed drive letter to D:") ShowDrives } else { LogWriter("Drive E: not found") } # change temp drive back to E: $drive = Get-WmiObject -Class win32_volume -Filter "DriveLetter = 'z:'" if ($null -ne $drive) { LogWriter("z: drive: $($drive.Label)") Set-WmiInstance -input $drive -Arguments @{ DriveLetter='E:' } LogWriter("changed drive letter to E:") ShowDrives } else { LogWriter("Drive Z: not found") } # change c:\pagefile.sys to e:\pagefile.sys ShowPageFiles $CurrentPageFile = Get-WmiObject -Query 'select * from Win32_PageFileSetting' if ($null -eq $CurrentPageFile) { LogWriter("No pagefile found") } else { $CurrentPageFile.delete() LogWriter("Old pagefile deleted") } ShowPageFiles Set-WMIInstance -Class Win32_PageFileSetting -Arguments @{name='e:\pagefile.sys';InitialSize = 0; MaximumSize = 0} LogWriter("set pagefile to e:\pagefile.sys") ShowPageFiles # reboot to activate pagefile LogWriter("Finally restarting session host") Restart-Computer -Force LogWriter("After Finally restarting session host") } } } LogWriter("Disable scheduled task") try { # disable startup scheduled task Disable-ScheduledTask -TaskName 'ITPC-AVD-Disk-Mover-Helper' } catch { LogWriter("Disabling scheduled task failed: " + $_.Exception.Message) } } elseif ($Mode -eq "RDAgentBootloader") { LogWriter("Installing AVD boot loader - current path is ${LocalConfig}") Start-Process -wait -FilePath "${LocalConfig}\Microsoft.RDInfra.RDAgentBootLoader.msi" -ArgumentList "/quiet /qn /norestart /passive" LogWriter("Waiting for the service RDAgentBootLoader") $bootloaderServiceName = "RDAgentBootLoader" $retryCount = 0 while ( -not (Get-Service "RDAgentBootLoader" -ErrorAction SilentlyContinue)) { $retry = ($retryCount -lt 6) LogWriter("Service RDAgentBootLoader was not found") if ($retry) { LogWriter("Retrying again in 30 seconds, this will be retry $retryCount") } else { LogWriter("Retry limit exceeded" ) throw "RDAgentBootLoader didn't become available after 6 retries" } $retryCount++ Start-Sleep -Seconds 30 } LogWriter("Disable scheduled task") try { # disable startup scheduled task Disable-ScheduledTask -TaskName 'ITPC-AVD-RDAgentBootloader-Helper' } catch { LogWriter("Disabling scheduled task failed: " + $_.Exception.Message) } } elseif ($Mode -eq "CleanFirstStart") { LogWriter("Cleaning up Azure Agent logs - current path is ${LocalConfig}") Remove-Item -Path "C:\Packages\Plugins\Microsoft.CPlat.Core.RunCommandWindows\*" -Include *.status -Recurse -Force -ErrorAction SilentlyContinue LogWriter("Disable scheduled task") try { # disable startup scheduled task Disable-ScheduledTask -TaskName 'ITPC-AVD-CleanFirstStart-Helper' } catch { LogWriter("Disabling scheduled task failed: " + $_.Exception.Message) } } elseif ($mode -eq "RestartBootloader") { $LogFile=$LogDir+"\AVD.AgentBootloaderErrorHandling.log" LogWriter "Stopping service" Stop-Service -Name "RDAgentBootLoader" LogWriter "Starting service" Start-Service -Name "RDAgentBootLoader" } elseif ($mode -eq "StartBootloader") { $LogFile=$LogDir+"\AVD.AgentBootloaderErrorHandling.log" LogWriter "Start service was triggered by an event" LogWriter "Waiting for 5 seconds" Start-Sleep -Seconds 5 LogWriter "Starting service" Start-Service -Name "RDAgentBootLoader" LogWriter "Waiting for 60 seconds" Start-Sleep -Seconds 60 LogWriter "Starting service (if not running)" Start-Service -Name "RDAgentBootLoader" LogWriter "Waiting for 60 seconds" Start-Sleep -Seconds 60 LogWriter "Starting service (if not running)" Start-Service -Name "RDAgentBootLoader" } # SIG # Begin signature block # MIIoawYJKoZIhvcNAQcCoIIoXDCCKFgCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU4qJrUnQJN2ErhFHujsk5VW1I # XQyggiGkMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B # AQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk # IElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw # ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz # 7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS # 5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7 # bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfI # SKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jH # trHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14 # Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2 # h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt # 6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPR # iQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ER # ElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4K # Jpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAd # BgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SS # y4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAC # hjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS # b290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRV # HSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyh # hyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO # 0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo # 8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++h # UD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5x # aiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIGrjCCBJag # AwIBAgIQBzY3tyRUfNhHrP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQG # EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl # cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIw # MzIzMDAwMDAwWhcNMzcwMzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UE # ChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQg # UlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEAxoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCw # zIP5WvYRoUQVQl+kiPNo+n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFz # sbPuK4CEiiIY3+vaPcQXf6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ # 7Gnf2ZCHRgB720RBidx8ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7 # QKxfst5Kfc71ORJn7w6lY2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/teP # c5OsLDnipUjW8LAxE6lXKZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCY # OjgRs/b2nuY7W+yB3iIU2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9K # oRxrOMUp88qqlnNCaJ+2RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6 # dSgkQe1CvwWcZklSUPRR8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM # 1+mYSlg+0wOI/rOP015LdhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbC # dLI/Hgl27KtdRnXiYKNYCQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbEC # AwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1N # hS9zKXaaL3WMaiCPnshvMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9P # MA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcB # AQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggr # BgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1 # c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAI # BgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7Zv # mKlEIgF+ZtbYIULhsBguEE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI # 2AvlXFvXbYf6hCAlNDFnzbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/ty # dBTX/6tPiix6q4XNQ1/tYLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVP # ulr3qRCyXen/KFSJ8NWKcXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmB # o1aGqwpFyd/EjaDnmPv7pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc # 6UsCUqc3fpNTrDsdCEkPlM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3c # HXg65J6t5TRxktcma+Q4c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0d # KNPH+ejxmF/7K9h+8kaddSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZP # J/tgZxahZrrdVcA6KYawmKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLe # Mt8EifAAzV3C+dAjfwAL5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDy # Divl1vupL0QVSucTDh3bNzgaoSv27dZ8/DCCBrwwggSkoAMCAQICEAuuZrxaun+V # h8b56QTjMwQwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoT # DkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJT # QTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTAeFw0yNDA5MjYwMDAwMDBaFw0z # NTExMjUyMzU5NTlaMEIxCzAJBgNVBAYTAlVTMREwDwYDVQQKEwhEaWdpQ2VydDEg # MB4GA1UEAxMXRGlnaUNlcnQgVGltZXN0YW1wIDIwMjQwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQC+anOf9pUhq5Ywultt5lmjtej9kR8YxIg7apnjpcH9 # CjAgQxK+CMR0Rne/i+utMeV5bUlYYSuuM4vQngvQepVHVzNLO9RDnEXvPghCaft0 # djvKKO+hDu6ObS7rJcXa/UKvNminKQPTv/1+kBPgHGlP28mgmoCw/xi6FG9+Un1h # 4eN6zh926SxMe6We2r1Z6VFZj75MU/HNmtsgtFjKfITLutLWUdAoWle+jYZ49+wx # GE1/UXjWfISDmHuI5e/6+NfQrxGFSKx+rDdNMsePW6FLrphfYtk/FLihp/feun0e # V+pIF496OVh4R1TvjQYpAztJpVIfdNsEvxHofBf1BWkadc+Up0Th8EifkEEWdX4r # A/FE1Q0rqViTbLVZIqi6viEk3RIySho1XyHLIAOJfXG5PEppc3XYeBH7xa6VTZ3r # OHNeiYnY+V4j1XbJ+Z9dI8ZhqcaDHOoj5KGg4YuiYx3eYm33aebsyF6eD9MF5IDb # PgjvwmnAalNEeJPvIeoGJXaeBQjIK13SlnzODdLtuThALhGtyconcVuPI8AaiCai # JnfdzUcb3dWnqUnjXkRFwLtsVAxFvGqsxUA2Jq/WTjbnNjIUzIs3ITVC6VBKAOlb # 2u29Vwgfta8b2ypi6n2PzP0nVepsFk8nlcuWfyZLzBaZ0MucEdeBiXL+nUOGhCjl # +QIDAQABo4IBizCCAYcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYD # VR0lAQH/BAwwCgYIKwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZI # AYb9bAcBMB8GA1UdIwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCPnshvMB0GA1UdDgQW # BBSfVywDdw4oFZBmpWNe7k+SH3agWzBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8v # Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2 # VGltZVN0YW1waW5nQ0EuY3JsMIGQBggrBgEFBQcBAQSBgzCBgDAkBggrBgEFBQcw # AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAChkxodHRwOi8v # Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hB # MjU2VGltZVN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQA9rR4fdplb # 4ziEEkfZQ5H2EdubTggd0ShPz9Pce4FLJl6reNKLkZd5Y/vEIqFWKt4oKcKz7wZm # Xa5VgW9B76k9NJxUl4JlKwyjUkKhk3aYx7D8vi2mpU1tKlY71AYXB8wTLrQeh83p # XnWwwsxc1Mt+FWqz57yFq6laICtKjPICYYf/qgxACHTvypGHrC8k1TqCeHk6u4I/ # VBQC9VK7iSpU5wlWjNlHlFFv/M93748YTeoXU/fFa9hWJQkuzG2+B7+bMDvmgF8V # lJt1qQcl7YFUMYgZU1WM6nyw23vT6QSgwX5Pq2m0xQ2V6FJHu8z4LXe/371k5QrN # 9FQBhLLISZi2yemW0P8ZZfx4zvSWzVXpAb9k4Hpvpi6bUe8iK6WonUSV6yPlMwer # wJZP/Gtbu3CKldMnn+LmmRTkTXpFIEB06nXZrDwhCGED+8RsWQSIXZpuG4WLFQOh # tloDRWGoCwwc6ZpPddOFkM2LlTbMcqFSzm4cd0boGhBq7vkqI1uHRz6Fq1IX7TaR # QuR+0BGOzISkcqwXu7nMpFu3mgrlgbAW+BzikRVQ3K2YHcGkiKjA4gi4OA/kz1YC # sdhIBHXqBzR0/Zd2QwQ/l4Gxftt/8wY3grcc/nS//TVkej9nmUYu83BDtccHHXKi # bMs/yXHhDXNkoPIdynhVAku7aRZOwqw6pDCCBugwggTQoAMCAQICEHe9DgW3WQu2 # HUdhUx4/de0wDQYJKoZIhvcNAQELBQAwUzELMAkGA1UEBhMCQkUxGTAXBgNVBAoT # EEdsb2JhbFNpZ24gbnYtc2ExKTAnBgNVBAMTIEdsb2JhbFNpZ24gQ29kZSBTaWdu # aW5nIFJvb3QgUjQ1MB4XDTIwMDcyODAwMDAwMFoXDTMwMDcyODAwMDAwMFowXDEL # MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExMjAwBgNVBAMT # KUdsb2JhbFNpZ24gR0NDIFI0NSBFViBDb2RlU2lnbmluZyBDQSAyMDIwMIICIjAN # BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyyDvlx65ATJDoFupiiP9IF6uOBKL # yizU/0HYGlXUGVO3/aMX53o5XMD3zhGj+aXtAfq1upPvr5Pc+OKzGUyDsEpEUAR4 # hBBqpNaWkI6B+HyrL7WjVzPSWHuUDm0PpZEmKrODT3KxintkktDwtFVflgsR5Zq1 # LLIRzyUbfVErmB9Jo1/4E541uAMC2qQTL4VK78QvcA7B1MwzEuy9QJXTEcrmzbMF # nMhT61LXeExRAZKC3hPzB450uoSAn9KkFQ7or+v3ifbfcfDRvqeyQTMgdcyx1e0d # BxnE6yZ38qttF5NJqbfmw5CcxrjszMl7ml7FxSSTY29+EIthz5hVoySiiDby+Z++ # ky6yBp8mwAwBVhLhsoqfDh7cmIsuz9riiTSmHyagqK54beyhiBU8wurut9itYaWv # cDaieY7cDXPA8eQsq5TsWAY5NkjWO1roIs50Dq8s8RXa0bSV6KzVSW3lr92ba2Mg # XY5+O7JD2GI6lOXNtJizNxkkEnJzqwSwCdyF5tQiBO9AKh0ubcdp0263AWwN4Jen # FuYmi4j3A0SGX2JnTLWnN6hV3AM2jG7PbTYm8Q6PsD1xwOEyp4LktjICMjB8tZPI # If08iOZpY/judcmLwqvvujr96V6/thHxvvA9yjI+bn3eD36blcQSh+cauE7uLMHf # oWXoJIPJKsL9uVMCAwEAAaOCAa0wggGpMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUE # DDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQlndD8 # WQmGY8Xs87ETO1ccA5I2ETAfBgNVHSMEGDAWgBQfAL9GgAr8eDm3pbRD2VZQu86W # OzCBkwYIKwYBBQUHAQEEgYYwgYMwOQYIKwYBBQUHMAGGLWh0dHA6Ly9vY3NwLmds # b2JhbHNpZ24uY29tL2NvZGVzaWduaW5ncm9vdHI0NTBGBggrBgEFBQcwAoY6aHR0 # cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvY29kZXNpZ25pbmdyb290 # cjQ1LmNydDBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vY3JsLmdsb2JhbHNpZ24u # Y29tL2NvZGVzaWduaW5ncm9vdHI0NS5jcmwwVQYDVR0gBE4wTDBBBgkrBgEEAaAy # AQIwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVw # b3NpdG9yeS8wBwYFZ4EMAQMwDQYJKoZIhvcNAQELBQADggIBACV1oAnJObq3oTmJ # Lxifq9brHUvolHwNB2ibHJ3vcbYXamsCT7M/hkWHzGWbTONYBgIiZtVhAsVjj9Si # 8bZeJQt3lunNcUAziCns7vOibbxNtT4GS8lzM8oIFC09TOiwunWmdC2kWDpsE0n4 # pRUKFJaFsWpoNCVCr5ZW9BD6JH3xK3LBFuFr6+apmMc+WvTQGJ39dJeGd0YqPSN9 # KHOKru8rG5q/bFOnFJ48h3HAXo7I+9MqkjPqV01eB17KwRisgS0aIfpuz5dhe99x # ejrKY/fVMEQ3Mv67Q4XcuvymyjMZK3dt28sF8H5fdS6itr81qjZjyc5k2b38vCzz # SVYAyBIrxie7N69X78TPHinE9OItziphz1ft9QpA4vUY1h7pkC/K04dfk4pIGhEd # 5TeFny5mYppegU6VrFVXQ9xTiyV+PGEPigu69T+m1473BFZeIbuf12pxgL+W3nID # 2NgiK/MnFk846FFADK6S7749ffeAxkw2V4SVp4QVSDAOUicIjY6ivSLHGcmmyg6o # ejbbarphXxEklaTijmjuGalJmV7QtDS91vlAxxCXMVI5NSkRhyTTxPupY8t3SNX6 # Yvwk4AR6TtDkbt7OnjhQJvQhcWXXCSXUyQcAerjH83foxdTiVdDTHvZ/UuJJjbkR # cgyIRCYzZgFE3+QzDiHeYolIB9r1MIIHsTCCBZmgAwIBAgIMK7DK+srufwlIJKxO # MA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxT # aWduIG52LXNhMTIwMAYDVQQDEylHbG9iYWxTaWduIEdDQyBSNDUgRVYgQ29kZVNp # Z25pbmcgQ0EgMjAyMDAeFw0yMzEyMTQxNjUwMTRaFw0yNjEyMTQxNjUwMTRaMIIB # FTEdMBsGA1UEDwwUUHJpdmF0ZSBPcmdhbml6YXRpb24xEzARBgNVBAUTCkhSQiAx # MDcyMDcxEzARBgsrBgEEAYI3PAIBAxMCREUxJDAiBgsrBgEEAYI3PAIBAhMTTm9y # ZHJoZWluLVdlc3RmYWxlbjEWMBQGCysGAQQBgjc8AgEBEwVLb2VsbjELMAkGA1UE # BhMCREUxHDAaBgNVBAgTE05vcmRyaGVpbi1XZXN0ZmFsZW4xETAPBgNVBAcTCE9k # ZW50aGFsMRowGAYDVQQJExFFaWNoaG9semVyIFdlZyAzNTEYMBYGA1UEChMPSVRQ # cm9DbG91ZCBHbWJIMRgwFgYDVQQDEw9JVFByb0Nsb3VkIEdtYkgwggIiMA0GCSqG # SIb3DQEBAQUAA4ICDwAwggIKAoICAQDUNE8fkODDhEVHbBTUlA9tuUVi8isUUcZG # 2fJSL7rYULBhd/vqUn0/mCuVjdDkW/8vlpuF1zKg29HZKkPIvPzrL4uAtZSFLbgB # exxg4Z4CEzARvEKC1R9P5EK05pKJP8y3nQmNOV2I9iYfiARkVMTKkYcRiQbDYrRh # E3oo9u0f/BD7Brn+4mcgKAI0VpdW3UDNyU5NqE+G/P8wa6qKNP+m0URZB6KYZeLe # RO8SECteMw91aG3rChBAODx5UYIEQBa0yg8ECC2QVVw4WXykAWCUvGKsv+Aij0xh # Zm+TLEnFdz6SsAVpeI1fB/jS4x58MLbjoMpdvlvpWCKR6/2GZcABnSIDtD8qOEr4 # YQ6AnO03u3tQGkDPGpYCLQN1/7CRWUwgQo4ExnRLRPIlTE517EmWiMufCVqC7jBI # tDgJrT/pN5AgQTjUWXW7gpnIopVnTP6F2JxTHGmB0IYaO9IznFufItRDWSIp9u20 # nOLjTk69rHU3C6T7oPLIKNtByKqXkFum3lMB/czEgfWouCaTvciGXEYpO5cYjkDD # /U0AkmsI0Kogr6qRBi+m5/lPr9FQGkJjJTm6F+A3K+zugDli0urn9ZGmoU5/I4Mj # FjquWsqmJfHv0WDNQgJ8Bwjsht0YgctYxWVa3wUQtBNU/AT9ul6pdccCo2rP5vk9 # kUSC9IIeywIDAQABo4IBtjCCAbIwDgYDVR0PAQH/BAQDAgeAMIGfBggrBgEFBQcB # AQSBkjCBjzBMBggrBgEFBQcwAoZAaHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNv # bS9jYWNlcnQvZ3NnY2NyNDVldmNvZGVzaWduY2EyMDIwLmNydDA/BggrBgEFBQcw # AYYzaHR0cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vZ3NnY2NyNDVldmNvZGVzaWdu # Y2EyMDIwMFUGA1UdIAROMEwwQQYJKwYBBAGgMgECMDQwMgYIKwYBBQUHAgEWJmh0 # dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMAcGBWeBDAEDMAkG # A1UdEwQCMAAwRwYDVR0fBEAwPjA8oDqgOIY2aHR0cDovL2NybC5nbG9iYWxzaWdu # LmNvbS9nc2djY3I0NWV2Y29kZXNpZ25jYTIwMjAuY3JsMBMGA1UdJQQMMAoGCCsG # AQUFBwMDMB8GA1UdIwQYMBaAFCWd0PxZCYZjxezzsRM7VxwDkjYRMB0GA1UdDgQW # BBSOHhUCE//hfBSzHQmywrj4QfLVdjANBgkqhkiG9w0BAQsFAAOCAgEAx+M4fm9+ # 1Y/8zjffzvduSiSGFB/m5GOAoS5Nf9MlkfDIhGrGLbd0CWwSeJC5alcT+hYNGc4o # ubRaw07pFkZY7UKrhM3IQk2cw+zrfCPf8jK05iiorqZPxovo4Mdg2/Qi9jN6CN/8 # /A925D71DiGCGcFJeaoQB6wedv0B0UyhM7ndErTobHPqZpyPXYLZtDooCRKP2ZOn # M1G2CgZB8RQ+sWcvwpvynRaT0i1WR0Cqm9d2y3oRs4qFHgSUYd0dO81iGDO6OvYx # EBFD9rAyrnH9Mm5GdLIOkPpCtnogmdycYRJ+AvZK2SwDHZ2dI6DQfmZvYXNO4ATc # t++AzngrLS9AaZg3Nq7JfTZKm1QTEusctAvDeA1fV93GOWqP/YUHoQ7ErBotAvsD # Bda+fpMcooi74Hm+hS1eroCB7YliEos7bPDWlccoXMohGWL4siX5exQ+C6vYi5Lz # 2ECbu9HDWIVnwj69GlzxTydWCWJWJs9RKhI8t1/9NPlsd9vnk3L09EqnG70KVMxT # RxBLD7G47dkSdC1QGfWTwqIl8qaNHqpIIrJgmBfj1nJ7+usLvRdoeW7L29NJuNEP # v8eN/MG11cDZq+uZuLzh7GGhzpuax9jao7IUdgmFNXw7yZs6KbBH/1gOTBHnxfrL # iPlMuk3LEK80KxnNt58u7zA9mer3LOxxMJkxggYxMIIGLQIBATBsMFwxCzAJBgNV # BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTIwMAYDVQQDEylHbG9i # YWxTaWduIEdDQyBSNDUgRVYgQ29kZVNpZ25pbmcgQ0EgMjAyMAIMK7DK+srufwlI # JKxOMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqG # SIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3 # AgEVMCMGCSqGSIb3DQEJBDEWBBT155vpLNn/zCvuUJF/OoN9Z9mvZjANBgkqhkiG # 9w0BAQEFAASCAgAnqf211Ldj3apKYpMmSGpbuvXzmUZHpwe+zZBtOO++PyPQv48B # hrOOZxpMkzXpDVJBsg66F2WILBq58dn2LPk+PUiHpP7dqK3pXP5+KpXUXHM/iJFw # gSjNAnKM01sxOUgBWA4d4MEQApdp3dkdLbCpihA9D4yHcsEg1VLALAZztJr1HQhI # 83rGsyW5eh946IkeD0LO9tE+tHfMf7bvjeEy+HofRVPWVAPQ/oxKKVlvLG7/jeDw # wWYDLXY5xAht4XYRD5zYCqgWRgpuzByIoAJ7EMZIE7JHOdbS0xnpnfzVGHLBlVvr # QNR4XWA4PO4mzrfxG2V0TWlA4ssyrZA7rsp82FFNIBVqYuHeiWFO5z8o3DKw78RG # O1yXCtvwUGlXh2ocnD5MsD909vEY7Vypcqy4HSMMGG5G2b6AVjfkekPZuLqqg2lZ # f/yqoxrZOfbFgV3Uo26HWUKnFTw2Kz4sTOOvnNhP6We+8mLcR3HrTAZDlTWMhIIH # C/pWEwaAhaFbl28RLMcBw3XuZOy10e8pear83XY3nMdUqpzUIwFGORbGY18VWvGX # fzlSwpVZ+3Tsy2onsl3ifxYrGVFByK7b4/oAzckMmpU5fPhGX8krstf95IOabkAP # rhkwXVAPd0mJ4HI8MUyW35IbyYag/fCOeEa4fJPDru18liRG5T+LB7tLd6GCAyAw # ggMcBgkqhkiG9w0BCQYxggMNMIIDCQIBATB3MGMxCzAJBgNVBAYTAlVTMRcwFQYD # VQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBH # NCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEAuuZrxaun+Vh8b56QTj # MwQwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwG # CSqGSIb3DQEJBTEPFw0yNTA0MDExMDM5NDZaMC8GCSqGSIb3DQEJBDEiBCBumrMs # CrgVYEXoNxTyhnwM/F77p7nZ+Lsz+199GM/agDANBgkqhkiG9w0BAQEFAASCAgAN # 9oXowh1UQb3j/rW4kCQSoAzcLvtCd5E8EhvnmBoQXjnIOPX4Zl81TSe+zaT2TwLs # KrCMPNpSNssL7F3T9C+N7KBTk8aNxqXXC3LBKJbnn5SQs6Bybo+rSEZ3rzHUhsag # vVJ44vJGGNyPkrFcrakjxfeH17MFObBgvt/sdJ7u/3g5/DFbvyrUCL1e/eOZ4CJU # AaiPMsKwaUHqASPZqrBQDFplVR1hPc/ACdHGWs/Oc+Xqp330JvxBCShwWL+NkIxY # cq8RyvaPSN6WIjjPVA9F/HRZNyL7c7t6dpzFzI0BEDvtfm2ymEgYUImMetMuJfLY # tEhG+Bj5F32L/E0IHgNq5l1iq+en0KFp8xMOVY+cW3hqdhz+h6afdUNmp0rdnd0m # rTG6hOPidvhZatxCD++6BwLUszV2kDSrbATUYmrXxNfJKz35QRRpZu8NBH2HjfKr # 5WV4LhsHo0vYE+IfXovPIwP+9iHZGvXCn0Qnu1YuVRerrTlRasMCzqPMynOiT+2u # Smi7DTjZ6yX3JcdjClLQq/Cgj7ecMwWaSeZ+QMCVbcNUy7RhCukhRXLau2SnITtw # npvV4gFZx71JeI9dvt1dmV/WaMjV3YMjcKjpIgq1TgDiMU1BpT+Ibuq1DJ45outm # dXdn2MIApshOkSke9u+6KVSJH7NMLG99N9a6d981nQ== # SIG # End signature block