Function Stop-Execution { <# .SYNOPSIS Breaks execution with specified error code. .DESCRIPTION Function break script execution with error code provided. Error code may be 0 in case of non-error stop. It also tries to parse ErrorRecord or Exception object (if provided) and logs this information. #> [CmdletBinding(DefaultParameterSetName="Exception")] param ( [Parameter(Position=1,ParameterSetName="Exception")] $InputObject = $null, [Parameter(ParameterSetName="ErrorString")] [String] $ExitString = "", [Parameter(ParameterSetName="ErrorString")] [Int] $ExitCode = 0, [Parameter(ParameterSetName="ErrorString")] [Switch] $Success ) Function Exit-Function { if ($ExitCode -eq 0) { Write-LogInfo ( "STOP ({0}):`n{1}" -f $ExitCode, $ExitString ) } else { Write-LogFatal ( "STOP ({0}):`n{1}" -f $ExitCode, $ExitString ) } Write-Log "__StopExecutionPreference__ = '$__StopExecutionPreference__'" switch ("$__StopExecutionPreference__") { "Exit" { exit $ExitCode } "ThrowIfException" { if ($InputObject -eq $null) { exit $ExitCode } else { throw $InputObject } } "ThrowAlways" { throw $InputObject } default { throw "Unknown value for __StopExecutionPreference__: '$__StopExecutionPreference__'" } } } switch($PSCmdlet.ParameterSetName) { "Exception" { #---------- if ($InputObject -eq $null) { $ExitString = "***** SCRIPT INTERRUPTED *****" $ExitCode = 255 Exit-Function } #---------- #---------- try { $ErrorRecord = [System.Management.Automation.ErrorRecord] $InputObject <# $ExitString = @" $($ErrorRecord.ToString()) *** Invocation Info *** $($ErrorRecord.InvocationInfo.PositionMessage) *** CategoryInfo *** $($ErrorRecord.CategoryInfo.ToString()) *** FullyQualifiedErrorId *** $($ErrorRecord.FullyQualifiedErrorId.ToString()) *** ScriptStackTrace *** $($ErrorRecord.ScriptStackTrace.ToString()) *** *** *** "@ #> $ExitString = Out-String -InputObject $InputObject $ExitCode = 255 Exit-Function } catch { $ErrorRecord = $null Write-LogWarning "Unable to cast InputObject to [System.Management.Automation.ErrorRecord]" } #---------- #---------- try { $Exception = [System.Exception] $InputObject #$ExitString = $Exception.ToString() $ExitString = Out-String -InputObject $InputObject $ExitCode = 255 Exit-Function } catch { $Exception = $null Write-LogWarning "Unable to cast InputObject to [System.Exception]" } #---------- #---------- try { $ExitString = Out-String -InputObject $InputObject $ExitCode = 255 Exit-Function } catch { Write-LogWarning "Unable to cast InputObject of type [$($InputObject.GetType())] to any of supported types." } #---------- } "ErrorString" { if ($Success) { $ExitString = "Script stopped with NO ERROR." $ExitCode = 0 } Exit-Function } } $ExitString = "Unknown error occured in Stop-Execution" $ExitCode = 255 Exit-Function } Function Get-PasswordAsSecureString { <# .SYNOPSIS Convert to / request password as secure string. #> [CmdletBinding()] param ( [String] $Password = "", [String] $Prompt = "Please enter password" ) if ($Password -eq "") { Read-Host -Prompt $Prompt -AsSecureString } else { ConvertTo-SecureString -String "$Password" -AsPlainText -Force } } Function New-Credential { <# .SYNOPSIS Create new creadential object with username and password provided. #> [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [String] $UserName, [String] $Password ) $SecurePassword = Get-PasswordAsSecureString -Password "$Password" New-Object System.Management.Automation.PSCredential( "$UserName", $SecurePassword ) } Function Invoke-WMSettingsChange { if (-not ("win32.nativemethods" -as [type])) { # Import SendMessageTimeout from Win32 Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @" [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr SendMessageTimeout( IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult); "@ } $HWND_BROADCAST = [IntPtr]0xFFFF $WM_SETTINGCHANGE = 0x001A $result = [UIntPtr]::Zero # Notify all windows of environment block change Write-Log "Executing 'SendMessageTimeout' ..." $retval = [Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, "Environment", 2, 5000, [ref] $result) Write-Log "'SendMessageTimeout' returned '$retval' (non-zero is OK)" } Function Start-Program { param ( [String] $FilePath, [String[]] $ArgumentList = @(' '), [Int] $Timeout = 0, [Switch] $NoWait, [Switch] $PassThru, [String] $WorkingDir = (Get-Location).ProviderPath ) trap { Write-LogError $_.Exception.Message return $null } Write-Log "Starting program: $FilePath $ArgumentList" $ProcessStartInfo = New-Object System.Diagnostics.ProcessStartInfo $ProcessStartInfo.FileName = $FilePath $ProcessStartInfo.Arguments = $ArgumentList $ProcessStartInfo.CreateNoWindow = $true $ProcessStartInfo.RedirectStandardOutput = $true $ProcessStartInfo.RedirectStandardError = $true $ProcessStartInfo.UseShellExecute = $false $ProcessStartInfo.WorkingDirectory = $WorkingDir $Process = [System.Diagnostics.Process]::Start($ProcessStartInfo) if ($NoWait) { if ($PassThru) { return $Process } else { return $null } } else { if ($Timeout -eq 0) { $Process.WaitForExit() } else { $Process.WaitForExit($Timeout) } } $ProcessResult = New-Object PSObject | Add-Member -Name "ExitCode" -MemberType NoteProperty -Value $Process.ExitCode -PassThru | Add-Member -Name "StdOut" -MemberType NoteProperty -Value $Process.StandardOutput.ReadToEnd() -PassThru | Add-Member -Name "StdErr" -MemberType NoteProperty -Value $Process.StandardError.ReadToEnd() -PassThru $Process = $null Write-Log ( "STDOUT:`n{0}" -f $ProcessResult.StdOut ) Write-Log ":STDOUT" Write-Log ( "STDERR:`n{0}" -f $ProcessResult.StdErr ) Write-Log ":STDERR" Write-Log "Program has finished with exit code ($($ProcessResult.ExitCode))" if ($PassThru) { return $ProcessResult } else { return $null } } New-Alias -Name Exec -Value Start-Program Function Backup-File { param ( [String] $Path ) $BackupFile = "$Path.bak" if (-not [IO.File]::Exists($Path)) { Write-LogError "Unable to backup file '$Path': file not exists." return } if ([IO.File]::Exists($BackupFile)) { try { [IO.File]::Delete($BackupFile) } catch { Write-LogError "Unable to delete existing .bak file '$BackupFile'." return } } Write-Log "Backing up file '$Path' to '$BackupFile'" [IO.File]::Copy($Path, $BackupFile, $true) } Function Install-Module { param ( [String] $InstallPath, [String] $ModulePath, [String] $ModuleName ) if ($ModuleName -eq "") { if ($ModulePath -eq "") { Stop-Execution -ExitString "Don't know which module should be installed." } else { $ModuleName = $ModulePath.Split("\")[-1] } } if ($InstallPath -eq "") { Stop-Execution -ExitString "To install the module destination path must be provided." } else { Write-Log "Installing the module to '$InstallPath'" $NewModulePath = [IO.Path]::Combine($InstallPath, $ModuleName) if ([IO.Directory]::Exists($NewModulePath)) { [IO.Directory]::Delete($NewModulePath, $true) } Copy-Item -Path $ModulePath -Destination $InstallPath -Recurse -Force -ErrorAction Stop Update-PsModulePath -AddPath "$InstallPath" } } Function Register-Module { param ( [String] $ModulePath ) $ModuleRoot = Split-Path -Path $ModulePath -Parent Write-Log "Registering the module at '$ModuleRoot'" Update-PsModulePath -AddPath "$ModuleRoot" } function Test-ModuleVersion { <# .SYNOPSIS Test module version. .DESCRIPTION Function specified module (current module by default), and compares it's version to version provided. Returned values: * -2 : error occured * -1 : module's version is lower than one provided * 0 : module's version is equal to one provided * 1 : module's version is greater than one provided #> param ( [String] $Name = "$__ModuleName", [String] $Version ) $ModuleVersion = (Get-Module -Name $Name -ListAvailable).Version if ($ModuleVersion -eq $null) { Write-Log "Module '$Name' not found." return -2 } try { $RequiredVersion = [System.Version]::Parse($Version) } catch { Write-Log "'$Version' is not a correct version string." return -2 } $ModuleVersion.CompareTo($RequiredVersion) }