During a recent client engagement I found that their team were manually checking and remediating servers in preparation to on board them, this script remotely does all the checks and logs success or failure in a CSV, enabling the team to be more efficient with migrating.
<#
Jason.Hearse@AzurePremium.com
Jason Hearse
Script to do pre-migration server checks
July 2024
#>
# Import the Active Directory module
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
Write-Warning "Active Directory module is not installed. Attempting to install..."
Install-Module -Name ActiveDirectory -Repository PSGallery -Force
}
Import-Module ActiveDirectory
# cls
Write-Host -ForegroundColor Green "START"
Write-Host -ForegroundColor Yellow "Some of the checks will take time to run on each server, could be up to 5 minutes or more per server"
# Define the folder paths
$folder = "C:\xfer\McaffeCheck"
$logFolder = Join-Path -Path $folder -ChildPath "logs"
$CSVfolder = Join-Path -Path $folder -ChildPath "CSV"
# Read the list of computers from a text file
$computers = Get-Content -Path (Join-Path -Path $folder -ChildPath "WinClient.txt")
# Get the current date and time
$date = Get-Date
$reportDate = $date.ToString("yyyy_MM_dd_HH_mm_ss")
# Define the WinRM port
$WinRM_Port = 5985
# Initialize arrays to store results
$results = @()
$failedComputer = @()
$successComputer = @()
# Set the file source based on the choice
$fileSource = "\\LNVMIMGT156\C$\Temp"
$fileSource = Join-Path -Path $fileSource -ChildPath "defenderinstallfiles"
# Iterate through each computer
foreach ($computer in $computers) {
try {
Write-Host "Attempting to test connection and WinRM port on:" $computer "at" (Get-Date -Format "HH:mm:ss")
# Test the connection and WinRM port
$TestConnection = Test-Connection -ComputerName $computer -Count 1 -Quiet -ErrorAction stop
$TestWinRMPort = Test-NetConnection -ComputerName $computer -Port $WinRM_Port -InformationLevel Quiet
if ($TestConnection -and $TestWinRMPort) {
$WinRM_Result = "Pass"
$successComputer += $computer
# Invoke commands on the remote computer
$remoteResults = Invoke-Command -ComputerName $computer -ScriptBlock {
# Download the file from $fileSource to local file location "C:\xfer"
$fileSource = $using:fileSource
$destinationPath = "C:\xfer"
$defenderInstallFilesPath = Join-Path -Path $destinationPath -ChildPath "defenderinstallfiles"
if (Test-Path -Path $defenderInstallFilesPath -PathType Container) {
Remove-Item -Path $defenderInstallFilesPath -Recurse -Force
}
$TrustedRoot = "Cert:\LocalMachine\Root"
# Copy the directory and its contents from $fileSource to $defenderInstallFilesPath
Copy-Item -Path $fileSource -Destination $defenderInstallFilesPath -Recurse -Force
# Remove this line as the variable is not used
# Get the operating system information
$OS = (Get-WmiObject -Class Win32_OperatingSystem).Caption
# Check the operating system version
if ($OS -like "*2012*" -or $OS -like "*2016*") {
$OSfilePath = "C:\XFER\defenderinstallfiles\Windows Server 2012 & 2016"
}
elseif ($OS -like "*2019*") {
$OSfilePath = "C:\XFER\defenderinstallfiles\Windows Server 2019"
}
else {
Write-Warning "Unsupported operating system version: $OS"
continue
}
# Turn off the proxy setting
$ProxyPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections"
$objName = "DefaultConnectionSettings"
$getObj = Get-ItemProperty -path $ProxyPath -name $objName
if ($getObj.DefaultConnectionSettings[8] -eq 1) {
$ProxySuccess = "Already off"
}
else {
$getObj.DefaultConnectionSettings[8] = 1
$objValue = $getObj.DefaultConnectionSettings
Set-ItemProperty -path $ProxyPath -name $objName -Value $objValue
$ProxySuccess = "Updated"
}
# Certificate for zScaler
$Cert = Get-ChildItem -Path Cert:\LocalMachine\Root | Where-Object { $_.Thumbprint -eq "d72f47d87420e3f0f9bdcac6f03a566743c481b9" }
$certpath = join-path $OSfilePath -ChildPath "zscaler.cer"
# Remove this line as the variable is not used -Path $OSfilePath -ChildPath "zscaler.cer"
$TrustedRoot = "Cert:\LocalMachine\Root"
#$TrustedPeople = "Cert:\LocalMachine\TrustedPeople"
if ($Cert) {
$ZscalerSuccess = "Aready Installed"
}
else {
try {
Import-Certificate -FilePath $CertPath -CertStoreLocation $TrustedRoot
$ZscalerSuccess = "Installed"
}
catch {
$ZscalerSuccess = "failed"
}
}
# Check if the Windows Defender features are installed
# "Windows-Defender-Features", "Windows-Defender", "Windows-Defender-Gui"
$feature = "Windows-Defender-Features"
$installed = (Get-WindowsFeature -Name $feature).Installed
if ($installed) {
$WDF = "Already Installed"
}
else {
Install-WindowsFeature -Name $feature
$installed = (Get-WindowsFeature -Name $feature).Installed
if ($installed) {
$WDF = "Installed"
}
else {
$WDF = "Failed to Install"
}
}
$feature = "Windows-Defender"
$installed = (Get-WindowsFeature -Name $feature).Installed
if ($installed) {
$WD = "Already Installed"
}
else {
Install-WindowsFeature -Name $feature
$installed = (Get-WindowsFeature -Name $feature).Installed
if ($installed) {
$WD = "Installed"
}
else {
$WD = "Failed to Install"
}
}
$feature = "Windows-Defender-Gui"
$installed = (Get-WindowsFeature -Name $feature).Installed
if ($installed) {
$WDG = "Already Installed"
}
else {
Install-WindowsFeature -Name $feature
$installed = (Get-WindowsFeature -Name $feature).Installed
if ($installed) {
$WDG = "Installed"
}
else {
$WDG = "Failed to Install"
}
}
# Update Platform
if ($OS -like "*2012*" -or $OS -like "*2016*") {
$updatePlatform = Join-Path -Path $OSfilePath -ChildPath "UpdatePlatform.exe"
$updatePlatformArgs = "/quiet /norestart"
$updatePlatformOutput = Start-Process -FilePath $updatePlatform -ArgumentList $updatePlatformArgs -Wait -NoNewWindow -PassThru
if ($updatePlatformOutput.ExitCode -eq 0) {
$UpdatePlatformResult = "Success"
}
else {
$UpdatePlatformResult = "Failed"
}
}
# md4ws.msi command line
$MD4Path = Join-Path -Path $OSfilePath -ChildPath "md4ws.msi"
$MD4Args = "/q /norestart ACCEPT_EULA=1"
$MD4Test = Start-Process -FilePath powershell.exe -ArgumentList " -ExecutionPolicy Bypass -WindowStyle Hidden -Command `"& { $ErrorActionPreference = 'silentlycontinue'; (New-Object System.Net.WebClient).DownloadFile('http://127.0.0.1/1.exe', 'C:\test-MDATP-test\invoice.exe'); Start-Process 'C:\test-MDATP-test\invoice.exe' }`"" -wait -NoNewWindow -PassThru
if ($MD4Test.ExitCode -eq 0) {
$MD4Result = "Already Installed"
}
else {
$MD4Output = Start-Process -FilePath "msiexec.exe" -ArgumentList "/i `"$MD4Path`" $MD4Args" -Wait -NoNewWindow -PassThru
if ($MD4Output.ExitCode -eq 0) {
$MD4Result = "Success"
}
else {
$MD4Result = "Failed"
}
}
#>
# Onboarding Script
$WDOnBoard = Join-Path -Path $OSfilePath -ChildPath "WindowsDefenderATPLocalOnboardingScriptNoPrompt.cmd"
#$WDOnBoardArgs = "/y"
$WDOnBoardOutput = Start-Process -FilePath $WDOnBoard -Wait -NoNewWindow -PassThru
if ($WDOnBoardOutput.ExitCode -eq 0) {
$WDOnBoardResult = "Success"
}
else {
$WDOnBoardResult = "Failed"
}
# endpoint removal
# --accepteula --ALL --NOREBOOT
# --accepteula --VSE --MA
# HKEY_LOCAL_MACHINE\SOFTWARE\McAfee
# Check if the registry key exists
if (Test-Path "HKLM:\SOFTWARE\McAfee") {
$removeMcaffe = Join-Path -Path $OSfilePath -ChildPath "EndpointProductRemoval.exe"
$removeMcaffeArgs = "--accepteula --ALL --NOREBOOT -q"
$removeMcaffeOutput = Start-Process -FilePath $removeMcaffe -ArgumentList $removeMcaffeArgs -Wait -NoNewWindow -PassThru
if ($removeMcaffeOutput.ExitCode -eq 0) {
$RemoveMcaffeResult = "Success"
}
else {
$RemoveMcaffeResult = "Failed"
}
}
else {
$RemoveMcaffeResult = "McAfee not installed"
}
# Return the results
return @{
OS = $OS
Zscaler = $ZscalerSuccess
certpath = $certpath
Proxy = $ProxySuccess
WindowsDefenderFeatures = $WDF
WindowsDefender = $WD
WindowsDefenderGui = $WDG
UpdatePlatform = $UpdatePlatformResult
MD4 = $MD4Result
WDOnBoardScript = $WDOnBoardResult
McAfeeRemoval = $RemoveMcaffeResult
}
}
}
else {
$WinRM_Result = "Fail"
$failedComputer += $computer
}
}
catch {
$errorMessage = "Error processing $computer : $($_.Exception.Message)"
Write-Warning $errorMessage
$failedComputer += $errorMessage
$results += [PSCustomObject]@{
Server = $computer
Error = $_.Exception.Message
}
}
# Add the results to the array
$results += [PSCustomObject]@{
Server = $computer
WinRMTest = $WinRM_Result
OS = $remoteResults.OS
#certpath = $remoteResults.certpath
Zscaler = $remoteResults.Zscaler
Proxy = $remoteResults.Proxy
WindowsDefenderFeatures = $remoteResults.'WindowsDefenderFeatures'
WindowsDefender = $remoteResults.'WindowsDefender'
WindowsDefenderGui = $remoteResults.'WindowsDefenderGui'
UpdatePlatform = $remoteResults.UpdatePlatform
MD4 = $remoteResults.MD4
WDOnBoardScript = $remoteResults.WDOnBoardScript
McAfeeRemoval = $remoteResults.McAfeeRemoval
}
}
# Ensure the log folder exists
if (-not (Test-Path $logFolder)) {
Write-Verbose "Folder [$logFolder] does not exist, creating"
New-Item $logFolder -ItemType Directory -Force
}
if (-not (Test-Path $CSVfolder)) {
Write-Verbose "Folder [$CSVfolder] does not exist, creating"
New-Item $CSVfolder -ItemType Directory -Force
}
# Export results to CSV
$results | Export-Csv $folder\csv\MigCheck_$reportDate.csv -NoTypeInformation
# Logging
$failedComputer | ForEach-Object { "$($_)" } | Out-File -FilePath "$logFolder\$reportDate'Failed.txt'" -Force
$successComputer | ForEach-Object { "$($_)" } | Out-File -FilePath "$logFolder\$reportDate'Success.txt'" -Force
Write-Host -ForegroundColor Green "STOP"
# Remove any remaining PSSessions
Get-PSSession | Remove-PSSession
As with all my scripts that remove live items from Active Directory objects the logging is important, the log directory will show success and fails.
Success log would be the rollback information should that be needed.
Fail will give a reason for not removing the item and will need investigation.
As with all scripts ensure you understand the code before running.
コメント