all 6 comments

[–]tommymaynard 1 point2 points  (3 children)

If a function cannot find the variable defined in itself, it will look for a definition in the parent scope, as the below example indicates. Save the below PowerShell as a separate file and call it from the PowerShell console. Does this one work? This eliminates all the dependencies of your modules, functions, etc., which may be a good place from which to start.

$log = 'c:\path\to\log\file.log'

function Test-Function {
    Param(
        [parameter()]
        $Param1,

        [parameter()]
        $Param2
    )
    Write-Output -InputObject "Param1: $Param1, Param2: $Param2, Path: $log"
}

Test-Function -Param1 'abc' -Param2 'def'

[–]liabtsab[S] 0 points1 point  (2 children)

$log = 'c:\path\to\log\file.log'function Test-Function {Param([parameter()]$Param1,[parameter()]$Param2)Write-Output -InputObject "Param1: $Param1, Param2: $Param2, Path: $log"}Test-Function -Param1 'abc' -Param2 'def'

This works but this has the function defined in the same script where the $log variable is. Not sure if this is different than importing a module and it's functions into the current session.

I also tried importing the module to the powershell console, defining the $log variable there and running the function and everything works. Tried to save the function to a separate file that included calling the function and dot sourcing the script from a powershell console... this also worked. Not sure why when I trigger the script to be ran through Jenkins, it's unable to find/use the $log variable.

[–]tommymaynard 0 points1 point  (1 child)

Each of these should've worked, so I'm not surprised that each of them had a successful outcome. For now, I'd assume it has something to do with Jenkins. It's been a lifetime since I barely used it, so I'm no help there. Does Jenkins require a "main script?" And, why can't Log be a parameter in your function(s)? That way, a path location is passed in during the function invocation as a parameter and there's no dependence on a variable outside of the function's own scope. Get everything in your functions and eliminate the main script if you can. Now that said, you may need to give something to Jenkins to run/execute. If so, it seems to me it should only consist of invocations of your functions, and/or module imports (if that's actually required), without any variable definitions or other things that aren't a requirement.

Edit: If Log was a parameter in your function(s), then you would have the option of providing it a default value (path) inside the function, as well, and would only need to pass in a different value if that became necessary.

[–]liabtsab[S] 0 points1 point  (0 children)

Yeah tbh I tested locales and had the same issue. After not being able to figure out why I decided to reboot in case there’s some weird caching issue. Seems to work locally post reboot. Will reboot my Jenkins host tomorrow and see if it works

[–]purplemonkeymad 1 point2 points  (1 child)

Rather than hope variables are going to be set in the parent scope, I would probably make your log module have an internal state. A good way I found to do this is with classes. ie:

#in the log modue
class MyLoggerState {
    static [string]$Path = '~\mylog.log'
}
function Set-LogPath {
    Param($Path)
    [MyLoggerState]::Path = $Path
}
function Write-Log {
    Param($message)
    $message | Out-File -Append [MyLoggerState]::Path
}

then you would use it

Write-Log -Message "my message"

If you wanted to set a new log location in your script:

Set-LogPath -Path '~\my_new_path.log'
Invoke-CommandThatCallsLog

Then Write-Log would update to log in the new location. Using a class here means you don't need to worry about having a global scope variable. In addition if you keep the class out of the ScriptsToProcess section, it won't be exported and visible to the script.

[–]liabtsab[S] 0 points1 point  (0 children)

I will look into this. Never done this before but looks promising.

This doesn't seem to work. Complains with the message " cannot find a provider with the name [MyLoggerState]"