Powershell脚本在直接运行时起作用,但在被另一个调用时却不起作用

时间:2019-12-11 13:15:54

标签: function powershell nested

我有一长串我想有点自动化的简单工作。这很简单,可以通过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 
            }
        }

1 个答案:

答案 0 :(得分:0)

对不起,如果我没有遵循程序或礼节,我是新来的。

如果您在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
}