【问题标题】:Powershell scripts work when run directly but not when called by anotherPowershell 脚本在直接运行时有效,但在被另一个脚本调用时无效
【发布时间】:2019-12-11 23:28:01
【问题描述】:

我有一长串简单的工作想要在某种程度上自动化。这很简单,通过 API 获取或发布信息并构建一些报告,没什么花哨的。

我决定构建一个主脚本,它指向各种其他脚本,每个脚本都处理自己的工作。这些小脚本中的每一个都引用了我构建的 Utility 脚本中的函数,该脚本具有所有其他简单作业脚本所共有的功能。

当我直接运行它们时,每个脚本都能完美运行,但是,当我尝试通过主脚本运行它们时,它们都会路由到它们,它们都失败了。

一个例子是,在许多情况下,我需要从 API 获取数据,但是当我需要 10k+ 时,我会限制为 1000 个对象返回。为了解决这个问题,我构建了一个递归调用自身的函数,直到没有更多数据需要收集。同样,这在单独调用时有效,但不是从主脚本调用时,由于某种原因,它在第一次运行后退出(在这种情况下应该运行 10 次以上)。然后,它什么也不返回。

我在想这可能与我如何确定函数/变量的范围有关?没有把握。我已经尝试将范围限定为Global, Local & Script,但似乎没有一个工作。这是一些代码...

*Master Director Script runs script based on user input*

...

&$choice_hash[$action].script_path
$ScriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
. "$ScriptDirectory\Utilities.psm1"

$user_data          = $null
$env_choice         = $null
$csv_output_path    = $null
$collated_user_data = [System.Collections.ArrayList]@()

function selectEnv {
    $global:env_choice = Read-Host @"
    > Select an Environment: [Prod] or [Dev]

    Your Choice
"@
    if ($env_choice -ne 'Prod' -and $env_choice -ne 'Dev') {
        consoleCmt $env_choice
        consoleCmt 'Invalid Choice. Try again...'
        selectEnv
    } else {
        if ($env_choice -eq 'Prod') {
            $global:csv_output_path = '\\etoprod\******\Exports\Report_Users_Prod.csv'  
        } else {
            $global:csv_output_path = '\\etoprod\******\Exports\Report_Users_Dev.csv'
        }

        $global:user_data = process_data $env_choice 'api/xm/1/people?embed=roles&limit=1000'
    }
}

function processUsersData {
     foreach($user in $user_data) {
        $user_roles     = ''
        $role_divider   = ','

        for($i = 0; $i -lt $user.roles.data.length; $i++) {
            # Only append a comma if there are more, otherwise leave blank for CSV deliniation 
            if ($i -eq $user.roles.data.length - 1) {
                $role_divider = ''
            }

            $user_roles += $user.roles.data[$i].name + $role_divider
        }

        # Build ordered hash table with above data
        $sanatized_user = [pscustomobject][ordered]@{id = $user.targetName; firstName = $user.firstName; lastName = $user.lastName; siteName = $user.site.name; roles = $user_roles }

        # Shovel into storage array used for building the CSV
        $global:collated_user_data += $sanatized_user
    }
}

notice 'Initiating Groups Report Script'
selectEnv
processUsersData
exportCsv $collated_user_data $csv_output_path

实用程序脚本(被调用的相关函数)

     $res      = $null
        $content  = @()

...

    function process_data($env, $url) {
            fetch_data $env $url

            foreach($i in $res.data) {
                $global:content += $i
            }

            if($res.links.next) {
                fetch_more $env $res.links.next
            }

            return $content  **Should return full collection of data, but fails after one pass**
        }

        function fetch_data($env, $url) {
            $base = generateEnvBase $env
            $path = "$base/$url"

            $req        = Invoke-WebRequest -Credential $cred -Uri $path -Method GET
            $global:res = ConvertFrom-Json $req
        }

        function fetch_more($env, $url) {
            $base = generateEnvBase $env
            $path = "$base$url"

            $req  = Invoke-WebRequest -Credential $cred -Uri $path -Method GET
            $res  = ConvertFrom-Json $req

            foreach($i in $res.data) {
                $global:content += $i
            }

            if($res.links.next) {
                fetch_more $env $res.links.next 
            }
        }

【问题讨论】:

    标签: function powershell nested


    【解决方案1】:

    如果我没有遵守程序或礼仪,请提前抱歉,我是新来的。

    如果您在 Main.ps1 中声明函数所需的所有变量,这应该可以工作。在函数内部创建要在函数外部使用的新变量时,也可以使用“脚本”范围。在函数内创建的示例 $Script:Var = "Stuff" 将可用于整个脚本。

    目录结构

    C:\Script\Root
    |   Main.ps1
    \---Utilities
            fetch_data.ps1
            fetch_more.ps1
            processUsersData.ps1
            process_data.ps1
            selectEnv.ps1
    

    Main.ps1

    #---[ Initization ]---#
    # Strings
    [String]$RootPath = $PSScriptRoot
    [String]$UtilPath = "$($RootPath)\Utilities"
    [String]$env_choice = $null
    [String]$csv_output_path = $null
    # Arrays
    [Array]$user_data = @()
    [Array]$content = @()
    [Array]$collated_user_data = @()
    [Array]$res = @()
    
    #---[ Source in Utilities ]---#
    # Get the scripts
    $Utilities = Get-ChildItem -Path "$UtilPath" -File | Where-Object {$_.Extension -eq ".ps1"}
    # Source in each one
    foreach ($Item in $Utilities) {
       .$Item.FullName
    }
    
    #---[ Select an Environment ]---#
    # Get the User's choice
    $env_choice = selectEnv
    # Process the choice
    switch ($env_choice) {
       Prod {
          $csv_output_path = '\\etoprod\******\Exports\Report_Users_Prod.csv'
          $user_data = process_data 'Prod' 'api/xm/1/people?embed=roles&limit=1000'
        }
       Dev {
          $csv_output_path = '\\etoprod\******\Exports\Report_Users_Dev.csv'
          $user_data = process_data 'Dev' 'api/xm/1/people?embed=roles&limit=1000'
        }
       Test {
          Write-Output "Test is not an option. Choose wisely."
          exit 1
        }
       Default {
          Write-Output "Unknown Environment Choice."
          exit 1
       }
    }
    
    #---[ Process Users and Export ]---#
    processUsersData
    exportCsv $collated_user_data $csv_output_path
    

    selectEnv.ps1

    function selectEnv {
       $Title = "Environment:"
       $Info = "Please choose an environment"
       # Options
       $Prod = New-Object System.Management.Automation.Host.ChoiceDescription '&Prod', 'Production environment'
       $Dev = New-Object System.Management.Automation.Host.ChoiceDescription '&Dev', 'Development environment'
       $Test = New-Object System.Management.Automation.Host.ChoiceDescription '&Test', 'Testing environment'
       $Options = [System.Management.Automation.Host.ChoiceDescription[]]($Prod, $Dev, $Test)
       $Default = 0
       # Promp the User
       $Choice =  $host.UI.PromptForChoice($Title , $Info , $Options, $Default)
       $Result = $Options[$Choice].Label -Replace '&',''
       return $Result
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-08
      • 1970-01-01
      • 2020-09-14
      • 2020-02-26
      • 2014-03-05
      • 2022-01-23
      • 1970-01-01
      • 2021-06-12
      • 1970-01-01
      相关资源
      最近更新 更多