Я выполняю рефакторинг ОГРОМНОГО скрипта, который мне нужен на работе, и я хочу использовать сплаттинг в нескольких служебных функциях, которые должны загружать различные файлы CSV. Моя проблема заключается в получении цели для файла данных. Ранее я использовал параметры REF, но когда я это делаю, это требует больше накладных расходов, потому что я не могу использовать вложенный объект внутри хеш-таблицы в качестве REF, поэтому он должен быть заключен в функцию, и это просто грязно при работе с таким количеством файлов. Я мог бы использовать свойство, перечисляющее имя конечного элемента, а затем жестко закодировать начало переменной ... но это не похоже на элегантное решение.
$m.DataFiles.('LDAP').HashArray = ...
Вот супер сокращенный фрагмент моего сценария:
################################################################################
############################# SCRIPT SETTINGS #############################
################################################################################
Set-StrictMode -Version latest;
$Global:ErrorActionPreference = 'Stop'; # Options: 'SilentlyContinue','Continue','Stop','Inquire'
$m = @{
DataFiles = @{
LDAP = @{
FilePath = 'C:\Temp\_PPtoO365_LDAP.csv'; ## Full path and file name: 'C:\Temp\log.csv';
Label = 'LdapFile'; ## If present, then I/O functions are written to log;
Append = $False; ## Should append vs re-write the file;
Fatal = $True; ## Should a read/write failure cause immediate script exit;
Dirty = $False; ## Used internally as a save flag;
Target = "`$m.DataFiles.LDAP.HashArray"; ## Name of variable for Load-HashArray();
DelimeterCSV = ','; ## CSV [column] delimeter;
DelimeterArray = ';'; ## Array delimeter (within a [column]);
HashArray = @(); ## Array of HashTable(s);
Template = [Ordered]@{ ## HashTable template for loading/saving;
SamAccountName = '';
MailNickname = '';
Mail = '';
Primaries = @();
Aliases = @();
};
};
};
Settings = @{
SaveExamples = $False;
SaveDebug = $False;
};
};
################################################################################
############################## MAIN ##############################
################################################################################
Function Do-Main() {
Write-Output ([string]::Format("[{0}] 'LDAP' records; Before.",$m.DataFiles.LDAP.HashArray.Length.ToString('#,##0')));
$params = $m.DataFiles.LDAP;
Load-HashArray1 @params;
Write-Output ([string]::Format("[{0}] 'LDAP' records; After Load-HashArray1().",$m.DataFiles.LDAP.HashArray.Length.ToString('#,##0')));
$m.DataFiles.LDAP.HashArray = @(); ## Reset
Write-Output ([string]::Format("[{0}] 'LDAP' records; After Reset.",$m.DataFiles.LDAP.HashArray.Length.ToString('#,##0')));
Load-HashArray2 @params;
Write-Output ([string]::Format("[{0}] 'LDAP' records; After Load-HashArray2().",$m.DataFiles.LDAP.HashArray.Length.ToString('#,##0')));
Set-Close;
Return;
}
Function Set-Close() {
## Script Cleanup - reduce HEAP ##
$m.Clear();
Exit(0);
}
################################################################################
############################## Functions ##############################
################################################################################
################################################################################
############################## Utility Functions ##############################
################################################################################
##### Function: Loads a CSV file #####
## Will return one of four types of collections:
## 1. If Target is @(), and no Template: Object[PSCustomObject] (default)
## 2. If Target is @(), and Template: Object[HashTable]
## 3. If Target is @{}, and no Template: HashTable [Ordered]@{index=PSCustomObject}
## 4. If Target is @{}, and Template: HashTable [Ordered]@{index=HashTable}
Function Load-HashArray1() {
Param (
[parameter(Mandatory=$True)][String] $FilePath, ## Full path and file name: 'C:\Temp\log.csv';
[parameter(Mandatory=$True)][String] $Label, ## If present, then I/O functions are written to log;
[parameter(Mandatory=$False)][Switch] $Append = $False, ## Should append vs re-write the file;
[parameter(Mandatory=$False)][Switch] $Fatal = $False, ## Should a read/write failure cause immediate script exit;
[parameter(Mandatory=$False)][Switch] $Dirty = $False, ## Used internally as a save flag;
[parameter(Mandatory=$True)][String] $Target, ## Name of variable to hold the HashArray;
[parameter(Mandatory=$False)][String] $DelimeterCSV = ',', ## CSV [column] delimeter;
[parameter(Mandatory=$False)][String] $DelimeterArray = ';', ## Array delimeter (within a [column]);
[parameter(Mandatory=$False)][Object[]] $HashArray = @(), ## Not used in this function;
[parameter(Mandatory=$False)][System.Collections.Specialized.OrderedDictionary] $Template = @{} ## HashTable template for loading/saving;
)
Write-Output "<<Debug1>> `$Target [$Target]... Expecting [`$m.DataFiles.LDAP.HashArray]";
$f = @{
Data = @($Template,$Template,$Template);
Target = $m.DataFiles.LDAP.HashArray;
TargetType = '';
};
Write-Output "<<Debug2>> `$f.Target [$($f.Target)]... Expecting []";
$f.TargetType = $f.Target.GetType().Name;
Write-Output "<<Debug3>> `$f.TargetType [$($f.TargetType)]... Expecting [Object[]]";
$Null = ($m.DataFiles.LDAP.HashArray = $f.Data);
Return;
}
Function Load-HashArray2() {
Param (
[parameter(Mandatory=$True)][String] $FilePath, ## Full path and file name: 'C:\Temp\log.csv';
[parameter(Mandatory=$True)][String] $Label, ## If present, then I/O functions are written to log;
[parameter(Mandatory=$False)][Switch] $Append = $False, ## Should append vs re-write the file;
[parameter(Mandatory=$False)][Switch] $Fatal = $False, ## Should a read/write failure cause immediate script exit;
[parameter(Mandatory=$False)][Switch] $Dirty = $False, ## Used internally as a save flag;
[parameter(Mandatory=$True)][String] $Target, ## Name of variable to hold the HashArray;
[parameter(Mandatory=$False)][String] $DelimeterCSV = ',', ## CSV [column] delimeter;
[parameter(Mandatory=$False)][String] $DelimeterArray = ';', ## Array delimeter (within a [column]);
[parameter(Mandatory=$False)][Object[]] $HashArray = @(), ## Not used in this function;
[parameter(Mandatory=$False)][System.Collections.Specialized.OrderedDictionary] $Template = @{} ## HashTable template for loading/saving;
)
Write-Output "<<Debug4>> `$Target [$Target]... Expecting [`$m.DataFiles.LDAP.HashArray]";
$f = @{
Data = @($Template,$Template,$Template);
Target = Invoke-Expression ($Target);
TargetType = '';
};
Write-Output "<<Debug5>> `$f.Target [$($f.Target)]... Expecting []";
$f.TargetType = $f.Target.GetType().Name;
Write-Output "<<Debug6>> `$f.TargetType [$($f.TargetType)]... Expecting [Object[] or HashTable]";
$Null = Invoke-Expression ($Target = $f.Data);
#$f.Target = $f.Data;
Return;
}
################################################################################
############################## Script Entry ##############################
################################################################################
Do-Main;
При выполнении возвращается:
[0] 'LDAP' records; Before.
<<Debug1>> $Target [$m.DataFiles.LDAP.HashArray]... Expecting [$m.DataFiles.LDAP.HashArray]
<<Debug2>> $f.Target []... Expecting []
<<Debug3>> $f.TargetType [Object[]]... Expecting [Object[]]
[3] 'LDAP' records; After Load-HashArray1().
[0] 'LDAP' records; After Reset.
<<Debug4>> $Target [$m.DataFiles.LDAP.HashArray]... Expecting [$m.DataFiles.LDAP.HashArray]
<<Debug5>> $f.Target []... Expecting []
Load-HashArray2 : You cannot call a method on a null-valued expression.
At C:\Temp\__Test.ps1:44 char:9
+ Load-HashArray2 @params;
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Load-HashArray2], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull,Load-HashArray2
Когда я закомментирую строку сразу после «Debug5», я получаю эту ошибку:
<<Debug5>> $f.Target []... Expecting []
<<Debug6>> $f.TargetType []... Expecting [Object[] or HashTable]
Invoke-Expression : The term 'System.Collections.Specialized.OrderedDictionary' is not recognized as the name of a
cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify
that the path is correct and try again.
At C:\Temp\__Test.ps1:119 char:17
+ $Null = Invoke-Expression ($Target = $f.Data);
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (System.Collecti...deredDictionary:String) [Invoke-Expression], CommandN
otFoundException
+ FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.InvokeExpressionCommand
Я использую этот блог для вдохновения (шаг 11): Powershell: динамическое создание имен переменных; Вложенные Hashtables