DeployLibNorEvo.psm1
<#
.SYNOPSIS This script contains all functions, including deploy session initialization .DESCRIPTION Script is "dot-sourced" from installation script in order to load functions. Start-NEDeploySession - Logging and temporary folder management. Inventory. Write-NELog - Writes events to script log Set-NELogonMaintenanceMessage - Set interactive logon message text Invoke-NEFileTransfer - Manages file transfers Invoke-NEWIMoperations - Handles mounting of WIM files to $Global:WorkingFolder\Mount folder Add-NEExitCode - Adds exit codes to be summarized to the script's exit code Invoke-NEInstallResult - Evaluates exit code and converts it to 0 (succeeded) or 1 (failure) Invoke-NEResetDeployEnvironment - Dismounts WIM files, closes processes and removes AppDeploy* variables Invoke-NEFinalAction - Called at last line of script to summarize exit codes, dismount wim files and remove temp directory Edit-NEIniFileContent - Manipulates content of INI files .NOTES Version history 1.0.0 2023-10-09 - Initial release (MKa) #> Function Start-NEDeploySession { [CmdletBinding()] $VerbosePreference = "Continue" #$VerbosePreference = "SilentlyContinue" ### Logging # Set logs folder $Global:Logpath = "C:\Logs" # Create log directory if missing (used for script and application logs) if (!( Test-Path $Global:Logpath -PathType Container )) { New-Item -ItemType "directory" -Path $Global:Logpath | Out-Null } # Script log name $Script:ScriptLogFile = $Global:Logpath + "\" + "$Global:ScriptName.log" # Rotate Script Log file if exist If (Test-Path -Path $Script:ScriptLogFile) { Get-ChildItem -Path $Script:ScriptLogFile | Where-Object { $_.BaseName -notmatch '\d{8}_\d{4}$' } | Rename-Item -NewName { "$($_.BaseName)-$($_.LastWriteTime.ToString('yyyyMMdd_HHmmss'))$($_.Extension)" }} # Create Script Log File if (!(Test-Path $Script:ScriptLogFile)) { New-Item $Script:ScriptLogFile -Type File | Out-Null } # Create a session unique folder name and create folder $Global:WorkingFolder = "C:\Deploy-" + (-join ((48..57) + (97..122) | Get-Random -Count 8 | ForEach-Object {[char]$_})) New-Item -ItemType "directory" -Path $Global:WorkingFolder | Out-Null # Check if MDT/SCCM session try { $TSenv = New-Object -COMObject Microsoft.SMS.TSEnvironment $Script:MDTIntegration = $true } catch { $Script:MDTIntegration = $false } finally { if ($Script:MDTIntegration) { $Script:TSLogpath = $TSenv.Value("LogPath") } } # Get originating process $repeat = $true $Process = Get-WmiObject Win32_Process -Filter "ProcessId = $pid" $ProcessTree = "$($Process.Name) (ID: $($Process.ProcessId))" # Get parent sessions recursively while ($repeat -eq $true) { $ProcessId = $Process.ParentProcessId $Process = Get-WmiObject Win32_Process -Filter "ProcessId = $ProcessId" if ($null -eq $Process -or $ProcessTree -like "*RuntimeBroker*") { $repeat = $false } else { $ProcessTree += "`n$($Process.Name) (ID: $($Process.ProcessId))" } } # Translate $Process into known processes switch -Wildcard ($ProcessTree) { "*KaseyaTaskRunnerx64*" { $OriginatingProcess = "Kaseya" } "*upKeeper*" { $OriginatingProcess = "upKeeper" } "*Intune*" { $OriginatingProcess = "Intune" } Default { $OriginatingProcess = "Unknown" } } # Check pending reboot status $PendingReboot = $false if ((get-childitem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" | Select-Object Name) -like '*RebootRequired*') { $PendingReboot = "$true" } if ((get-childitem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing" | Select-Object Name) -like '*RebootPending*') { $PendingReboot = "$true" } # Check if user executing script is elevated ($UserElevated) $e = New-Object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent()) if ($e.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { $UserElevated = $true } else { $UserElevated = $false } # Remove ExitCode variable (if exists) if ($script:DeployExitCode) { Remove-Variable DeployExitCode -Scope Script } # Set initial error code value = 0 $script:DeployExitCode = 0 # Perfom inventory $InvComputerMake = (Get-WmiObject -Class:Win32_ComputerSystem).Manufacturer $InvComputerSerialNumber = (Get-WmiObject win32_bios).SerialNumber $InvComputerModel = (Get-WmiObject -Class:Win32_ComputerSystem).Model $InvComputerSystemfamily = (Get-WmiObject -Class:Win32_ComputerSystem).SystemFamily $InvSysdrvFreeSpace = [math]::Round(((Get-WmiObject -Class Win32_logicaldisk -Filter "DeviceID = 'C:'").Freespace /1GB),0) $InvFunctionsLibVer = (Get-Module | Where-Object { $_.Name -eq "DeployLibNorC" }).Version.ToString() if (!($User)) { $User = "N/A" } # Log system and session info Write-NELog " " Write-NELog "### System" Write-NELog "Computer Name: $env:computername" Write-NELog "Serial Number: $InvComputerSerialNumber" Write-NELog "Make: $InvComputerMake" Write-NELog "Model: $InvComputerModel" Write-NELog "Model info: $InvComputerSystemfamily" Write-NELog " " Write-NELog "### Session" Write-NELog "Originating Process: $OriginatingProcess" Write-NELog "Functions Library Version: $InvFunctionsLibVer" Write-NELog "MDT/SCCM Session: $Script:MDTIntegration" Write-NELog "ScriptDir: $Global:ScriptDir" Write-NELog "ScriptName: $Global:ScriptName" Write-NELog "Script Log: $Script:ScriptLogFile" Write-NELog "WorkingFolder: $Global:WorkingFolder" Write-NELog "Available disk space: $InvSysdrvFreeSpace GB" Write-NELog "Pending reboot: $PendingReboot" Write-NELog "Credentails supplied for user: $User" Write-NELog "Script running elevated: $UserElevated" Write-NELog " " Write-NELog "### Custom actions" } Function Write-NELog { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Message, [Parameter()] [ValidateSet(1, 2, 3)] [string]$LogLevel = 1, [Parameter()] [string]$WriteToScreen = $true ) $TimeGenerated = "$(Get-Date -Format HH:mm:ss).$((Get-Date).Millisecond)+000" $TimeGeneratedHMS = "$(Get-Date -Format HH:mm:ss)" $Line = '<![LOG[{0}]LOG]!><time="{1}" date="{2}" component="{3}" context="" type="{4}" thread="" file="">' $LineFormat = $Message, $TimeGenerated, (Get-Date -Format MM-dd-yyyy), "$($Global:ScriptName | Split-Path -Leaf):$($MyInvocation.ScriptLineNumber)", $LogLevel $Line = $Line -f $LineFormat Add-Content -Value $Line -Path $Script:ScriptLogFile if($WriteToScreen -eq $true) { switch ($LogLevel) { '1' { Write-Host $TimeGeneratedHMS "-" $Message -ForegroundColor Gray } '2' { Write-Host $TimeGeneratedHMS "-" $Message -ForegroundColor Yellow } '3' { Write-Host $TimeGeneratedHMS "-" $Message -ForegroundColor Red } Default {} } } # if ($writetolistbox -eq $true) { $result1.Items.Add("$Message") } } Function Set-NELogonMaintenanceMessage { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [string]$AppName ) Write-NELog "Setting logon message for application $AppName" # [void](New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "LegalNoticeCaption" -PropertyType String -Value "Systemunderh�ll" -Force) # [void](New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "LegalNoticeText" -PropertyType String -Value "Applikationen $AppName $Action. V�nligen v�nta med att logga in tills datorn har startas om och detta meddelande inte l�gre visas n�r du trycker Ctrl + Alt + Delete f�r att l�sa upp datorn." -Force) } [void](New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "LegalNoticeCaption" -PropertyType String -Value "System Maintenence" -Force) [void](New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "LegalNoticeText" -PropertyType String -Value "Applikationen $AppName $Action. V�nligen v�nta med att logga in tills datorn har startas om och detta meddelande inte l�gre visas n�r du trycker Ctrl + Alt + Delete f�r att l�sa upp datorn." -Force) Function Invoke-NEFileTransfer { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [string]$URL, [Parameter(Mandatory=$false)] [INT]$DownloadAttempts = 3, [Parameter(Mandatory=$false)] [INT]$VerifySeconds = 5 ) # Create Secure String for package downloads if -User and -Pass arguments were passed from command line if (($User) -and ($Pass)) { $SecPass = ConvertTo-SecureString $Pass -asplaintext -force $Credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $User,$SecPass } #Inital values $a = 1 #$result.InternalErrorCode = "1" while ($result.InternalErrorCode -ne 0 -and $a -le $DownloadAttempts) { # Get file name $filename = $URL.Split('/')[-1] # Create random BITS Transfer ID $id = (-join ((48..57) + (97..122) | Get-Random -Count 8 | ForEach-Object { [char]$_} )) # Initiate transfer - with/without credentials if ($Credentials) { Write-NELog -Message "Initiating download of file $filename" Write-NELog -Message "using supplied credentials - attempt $a of $DownloadAttempts" [Void](Start-BitsTransfer -Authentication Basic -Credential $Credentials -Asynchronous -DisplayName $id -Source $URL -Destination $Global:WorkingFolder) } else { Write-NELog -Message "Initiating download of file $filename" Write-NELog -Message "No credentials specified - attempt $a of $DownloadAttempts" [Void](Start-BitsTransfer -Asynchronous -DisplayName $id -Source $URL -Destination $Global:WorkingFolder) } # Wait for transfer to complete while (((Get-BitsTransfer | Where-Object {($_.DisplayName -eq $id)}).JobState -eq "Connecting") -or ((Get-BitsTransfer | Where-Object {($_.DisplayName -eq $id)}).JobState -eq "Transferring")) { Start-Sleep -Seconds 1 } # Get finish time $finishtime = Get-Date # Get result before completing #$result = (Get-BitsTransfer | Where-Object {($_.DisplayName -eq $id)}).InternalErrorCode $result = Get-BitsTransfer | Where-Object {$_.DisplayName -eq $id} | Select-Object * # Complete transfer Get-BitsTransfer | Complete-BitsTransfer # Report successfull download and write stats. If ($result.InternalErrorCode -eq 0) { # Get file size in appropriate unit switch ($result.BytesTransferred) { {$_ -ge 0 -and $_ -le 1024} { $transferSize = $_ ; $transferUnit = 'B' } {$_ -ge 1025 -and $_ -le 1024000} { $transferSize = [math]::Round($_ / 1KB ,2) ; $transferUnit = 'KB' } {$_ -ge 1024001 -and $_ -le 1024000000} { $transferSize = [math]::Round($_ / 1MB ,2) ; $transferUnit = 'MB'} {$_ -ge 1024000001} { $transferSize = [math]::Round($_ / 1GB ,2) ; $transferUnit = 'GB'} } # Get transfer time in seconds $transfertime = (New-TimeSpan -Start $result.CreationTime -End $finishtime).Seconds # Get transfer speed $transferspeeed = [math]::Round(($result.BytesTransferred / $transfertime)/ 1MB ,2) Write-NELog "Download succeeded on attempt $a" Write-NELog "Transfer statistics" Write-NELog " File size: $transferSize $transferUnit" Write-NELog " Transfer time: $transfertime second(s)" Write-NELog " Average speed: $transferspeeed MB/s" # Wait $VerifySeconds seconds and check if file still exists Start-Sleep -Seconds $VerifySeconds If (Test-Path -Path "$Global:WorkingFolder\$filename") { Add-NEExitCode -ExitCode 0 ; Write-NELog -Message "File remains after $VerifySeconds seconds" } else { Add-NEExitCode -ExitCode 1 ; Write-NELog -Message "File missing after $VerifySeconds seconds. Check Anti Virus / Anti Malware!" -LogLevel 3} } # If download failed, report unsuccessful attempt and wait 5-10 seconds, if not last attempt else { Write-NELog "Download attempt $a failed" # If download attempts remains, Increment attempt counter by 1 and wait 5-10 seconds If ($a -lt $DownloadAttempts) { $a = $a + 1 Start-sleep -Seconds (5..10 | get-random) } # If no download attempt remains, Add Exit Code 1, Write red message and Invoke-FinalAction else { Add-NEExitCode -ExitCode 1 ; Write-NELog -Message "Download FAILED - Exiting script!" -LogLevel 3 Invoke-FinalAction } } } } Function Invoke-NEWIMoperations { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [string]$WIMfile ) # Create mount directory if missing [Void](if (!(Test-Path "$Global:WorkingFolder\mount")) { New-Item -ItemType Directory -Path "$Global:WorkingFolder\mount" }) # Mount wim file Write-NELog -Message "Mount $WIMfile to $Global:WorkingFolder\mount" [Void](Mount-WindowsImage -ImagePath "$Global:WorkingFolder\$WIMfile" -Index 1 -Path "$Global:WorkingFolder\Mount") # Check result $m = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\WIMMount\Mounted Images" | Get-ItemProperty | Where-Object "WIM Path" -eq $Global:WorkingFolder\$WIMfile if ($m.Status) { Write-NELog -Message "$WIMfile was mounted to $Global:WorkingFolder\mount" Add-NEExitCode -ExitCode 0 } else { Write-NELog -Message "Mount FAILED" -LogLevel 3 Add-NEExitCode -ExitCode 1 } } Function Add-NEExitCode { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [INT]$ExitCode, [Parameter(Mandatory=$false)] [INT]$RebootRequired ) # set $script:DeployExitCode = 1 if not exist prior, else add to existing if (!($script:DeployExitCode)) { $script:DeployExitCode = $ExitCode } else { $script:DeployExitCode +=$ExitCode } # set $script:RebootRequired if ($RebootRequired -eq 1) { $script:RebootRequired = 1 } } Function Invoke-NEInstallResult { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [string]$ExitCode ) # Exit code 0 - The action completed successfully (ERROR_SUCCESS) If (($ExitCode -eq 0) -or ($ExitCode -eq 0x80070000 )) { Add-NEExitCode -ExitCode 0 Write-NELog -Message "Operation Succeeded (0)" } # Exit code 1638 (999) - Another version of this product is already installed (ERROR_PRODUCT_VERSION) elseIf (($ExitCode -eq 1638) -or ($ExitCode -eq 666) -or ($ExitCode -eq 0x80070666 )) { Add-NEExitCode -ExitCode 0 Write-NELog -Message "Operation Succeeded ($ExitCode - product already installed)" -LogLevel 2 } # Exit code 1605 (645) - This action is only valid for products that are currently installed. (ERROR_UNKNOWN_PRODUCT) elseIf (($ExitCode -eq 1605) -or ($ExitCode -eq 645) -or ($ExitCode -eq 0x80070645 )) { Add-ExitCode -ExitCode 0 Write-Log -Message "Operation Succeeded $ExitCode - product not installed on system" -LogLevel 2 } # Exit code 3010 - restart is required to complete the install (ERROR_SUCCESS_REBOOT_REQUIRED) elseIf (($ExitCode -eq 3010) -or ($ExitCode -eq 0x80070bc2 )) { Add-NEExitCode -ExitCode 0 -RebootRequired 1 Write-NELog -Message "Operation Succeeded (3010 - reboot required)" -LogLevel 1 } # Exit code 1707 - Installation operation completed successfully (ERROR_SUCCESS) elseIf (($ExitCode -eq 1707) -or ($ExitCode -eq 0x800706ab )) { Add-NEExitCode -ExitCode 0 Write-NELog -Message "Operation Succeeded (1707)" } # Exit code 1618 - another installation is already in progress (ERROR_INSTALL_ALREADY_RUNNING) elseIf (($ExitCode -eq 1618) -or ($ExitCode -eq 0x80070652 )) { Write-NELog -Message "Windows installer already running (1618 - another installation is already in progress) - EXITING SCRIPT" -LogLevel 3 # Breaking error - exit script with error code 1618 $script:WindowsInstallerBusy = 1 Invoke-NEFinalAction } # Exit code anything else else { Add-NEExitCode -ExitCode 1 Write-NELog -Message "Operation FAILED ($ExitCode)" -LogLevel 3 } Start-Sleep -Seconds 2 } Function Invoke-NEResetDeployEnvironment { # Dismount wim image if mounted if ((Test-Path -Path "HKLM:\SOFTWARE\Microsoft\WIMMount\Mounted Images") -and (Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\WIMMount\Mounted Images" | Get-ItemProperty | Where-Object "Mount Path" -eq "$Global:WorkingFolder\Mount")) { if ((Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\WIMMount\Mounted Images" | Get-ItemProperty | Where-Object "Mount Path" -eq "$Global:WorkingFolder\Mount").Status) { Write-NELog -Message "Mounted Windows images detected (WIM file mounted)" # Close any open explorer windows Write-NELog -Message "Close any Explorer windows ($Global:WorkingFolder\Mount)" $shell = New-Object -ComObject Shell.Application $window = $shell.Windows() | Where-Object { $_.LocationURL -like "$(([uri]"$Global:WorkingFolder\Mount").AbsoluteUri)*" } $window | ForEach-Object { $_.Quit() } # Close any running processes Write-NELog -Message "Close any runnig processes ($Global:WorkingFolder\Mount)" get-process | Where-Object { $_.Path -like "$Global:WorkingFolder\Mount\*" } | ForEach-Object { Stop-Process -Name $_.Name -Force -ErrorAction SilentlyContinue } Start-Sleep -Seconds 5 # Dismount image try { Write-NELog -Message "Dismount $Global:WorkingFolder\Mount" Dismount-WindowsImage -Path "$Global:WorkingFolder\Mount" -Discard $Script:WimStatus = $true Write-NELog "Windows image successfully dismounted." } catch { # Failed to Dismount normally. Setting up a scheduled task to unmount after next reboot (exit code 3010) Write-NELog -Message "Dismount $Global:WorkingFolder\Mount failed. Setting scheduled task to perform dismount after next reboot." -LogLevel 2 $Script:WimStatus = $false Add-NEExitCode -ExitCode 3010 $STAction = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument '-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -command "& {Get-WindowsImage -Mounted | Where-Object {$_.MountStatus -eq ''Invalid''} | ForEach-Object {$_ | Dismount-WindowsImage -Discard -ErrorVariable wimerr; if ([bool]$wimerr) {$errflag = $true}}; If (-not $errflag) {Clear-WindowsCorruptMountPoint; Unregister-ScheduledTask -TaskName ''CleanupWIM'' -Confirm:$false}}"' $STTrigger = New-ScheduledTaskTrigger -AtStartup Register-ScheduledTask -Action $STAction -Trigger $STTrigger -TaskName "CleanupWIM" -Description "Clean up WIM Mount points that failed to dismount" -User "NT AUTHORITY\SYSTEM" -RunLevel Highest -Force } } } # Remove all AppDeploy* variables Write-NELog -Message "Remove AppDeploy* variables" Get-Variable | Where-Object { $_.Name -Like "*AppDeploy*" } | Remove-Variable -ErrorAction SilentlyContinue } Function Invoke-NEFinalAction { Write-NELog -Message " " Write-NELog -Message "### Final Actions" # Reset environment - Dismount any mounted Windows Images (WIM) files Invoke-NEResetDeployEnvironment # Remove temporary folder if $Script:WimStatus is $true if ( $Script:WimStatus = $true ) { # Close any open explorer windows Write-NELog -Message "Close any Explorer windows ($Global:WorkingFolder)" $shell = New-Object -ComObject Shell.Application $window = $shell.Windows() | Where-Object { $_.LocationURL -like "$(([uri]"$Global:WorkingFolder").AbsoluteUri)*" } $window | ForEach-Object { $_.Quit() } # Close any running processes Write-NELog -Message "Close any runnig processes ($Global:WorkingFolder)" get-process | Where-Object { $_.Path -like "$Global:WorkingFolder\*" } | ForEach-Object { Stop-Process -Name $_.Name -Force -ErrorAction SilentlyContinue } Write-NELog -Message "Remove temporary folder $Global:WorkingFolder" Remove-Item $Global:WorkingFolder -Recurse -Force if (!(Test-Path -Path $Global:WorkingFolder)) { Write-NELog "Temporary folder was successfully removed" } else { Write-NELog -Message "FAILURE - Temorary folder could not be removed." -LogLevel 3 } } else { Write-NELog -Message "FAILURE - Windows Image dismount FAILED. Wim mount, temporary folder and files will remain on computer and must be removed manually." -LogLevel 3 } # Remove logon maintenance message Write-NELog "Removing logon message" [void](New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "LegalNoticeCaption" -PropertyType String -Value "" -Force) [void](New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "LegalNoticeText" -PropertyType String -Value "" -Force) # Exit with "1618" if $script:WindowsInstallerBusy is 1 if ($script:WindowsInstallerBusy -eq 1) { Write-NELog -Message " " Write-NELog -Message "Final status: FAILURE - Windows installer already running (1618)" # Copy script log to TS log path if $Script:MDTIntegration is true if ($true -eq $Script:MDTIntegration) { Copy-Item -Path $ScriptLogFile -Destination $Script:TSLogpath } Start-Sleep -Seconds 1 Exit 1618 } elseif ( ($script:DeployExitCode -eq 0) -and ($script:RebootRequired -eq 1) ) { Write-NELog -Message " " Write-NELog -Message "Final status: Success - reboot required (3010)" # Copy script log to TS log path if $Script:MDTIntegration is true if ($true -eq $Script:MDTIntegration) { Copy-Item -Path $ScriptLogFile -Destination $Script:TSLogpath } Start-Sleep -Seconds 1 Exit 3010 } # Exit with "0" if exit code is missing or $script:DeployExitCode is 0 and $script:RebootRequired is not 1 (or missing) elseif ( (!($script:DeployExitCode)) -or ($script:DeployExitCode -eq 0)) { Write-NELog -Message " " Write-NELog -Message "Final status: SUCCESS (0)" # Copy script log to TS log path if $Script:MDTIntegration is true if ($true -eq $Script:MDTIntegration) { Copy-Item -Path $ScriptLogFile -Destination $Script:TSLogpath } Start-Sleep -Seconds 1 Exit 0 } # Exit with "1" if $script:DeployExitCode is > 0 else { Write-NELog -Message " " Write-NELog -Message "Final status: FAILURE (1)" -LogLevel 3 # Copy script log to TS log path if $Script:MDTIntegration is true if ($true -eq $Script:MDTIntegration) { Copy-Item -Path $ScriptLogFile -Destination $Script:TSLogpath } Start-Sleep -Seconds 5 Exit 1 } } Function Edit-NEIniFileContent { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [string]$IniFile, [Parameter(Mandatory=$true)] [String]$Content, [Parameter(Mandatory=$true)] [String]$Section, [Parameter(Mandatory=$true)] [String]$Value ) if (Test-Path -Path $IniFile) { # Install NuGet package manager if missing try { $packages = (Get-PackageProvider).name if (!($packages -like ("NuGet"))) { Install-PackageProvider -name NuGet -Force } Import-Module PsIni -Force } catch { Install-Module -Scope CurrentUser PsIni -Force Import-Module PsIni -Force } if ( $Content -ne (Get-IniContent $IniFile)[$Section][$Value]) { $ini = Get-IniContent $IniFile $ini[$Section][$Value] = $Content $ini | Out-IniFile -Force -Encoding Unicode -FilePath $IniFile Write-NELog -Message "INI file $IniFile content has been added or modified" Invoke-NEInstallResult -ExitCode 0 } else { Write-NELog -Message "Content of $IniFile is was up to date, no changees were made" -LogLevel 2 Invoke-NEInstallResult -ExitCode 0 } } else { Write-NELog -Message "$IniFile was not found" -LogLevel 3 Invoke-NEInstallResult -ExitCode 1 } } |