I've been going through Don Jones videos from CBTNuggets (they are great).
I'm starting to separate my scripts into "tools" and "coordination/process" scripts. My scripts are as follows:
Script1: Import-CSV and output the object.
I don't know how to retrieve the object properly in Script2. Any hlep is appreciated.
#Script1.ps1 [CmdletBinding()] param( [Parameter(Mandatory=$True)] [string]$csv ) $obj = Import-CSV $csv Write-Output $obj
#Script3.ps1 Script1.ps1 -csv Servers.csv | Script2.ps1
Encodes -MyParam to accept pipeline input of objects of the type "object." See "about_functions_advanced_parameters" in the shell.
The object type is important. If Script1 is outputting strings, then -MyParam should be of type [string]. Note that [string] is fine if you'll *only ever provide pipeline input or one item at a time*.
So, this isn't a question of "retrieving the object in Script2." Scripts only accept input via parameters; you have to tell PowerShell which parameter(s) should accept the incoming pipeline stuff.
Thanks so much! I'm a step further... maybe I'm complicating it. What I'm trying to do is script1 import list of servers. script2 execute a command for each server.
Here's the results from each script. I've tried to ForEach which didn't work out. Do I need to split $MyParam? Here's the Verbose output:
Well, a couple of things. You need to keep watching the videos, maybe. I feel like you've maybe skipped ahead a bit and missed some of the basics about how PowerShell manages pipeline input. When you write a pipeline function or script, it has to have a particular form.
The PROCESS block is needed to tell the shell what bit of your script is processing pipeline objects. But because your parameter is an array, you still need to enumerate it. Now, this assumes you're piping strings into it. A CSV isn't a string.
But it's really tough to help further when I'm not seeing everything. For example, I've no idea why Out-String is being brought into this, and depending on what you're doing, it could be resulting in you not getting what you want. You need to pay attention to the difference between dealing with ONE of something, and dealing with a COLLECTION of somethings. You also need to understand that PowerShell likes dealing with objects, not text. Out-String produces text. When you convert an object to text, you remove much of the shell's ability to comprehend and manipulate that object.
You should try and get out of the habit of using Out-String unless you're in a specific situation where you NEED it, and you KNOW you need it. For example, I would construct a verbose like this:
If $thing contains a string, that's all you need to do.
But this all comes down to input. For example, suppose I have a CSV file that has a ComputerName column. I could NOT Import-CSV that and pipe it to the script, using the parameters defined here. Import-CSV would produce objects having ComputerName properties – not strings. If that Import-CSV was the goal:
Now the -MyParam parameter can accept incoming strings, or it can accept incoming objects that have a MyParam property. Changing that:
Now the -ComputerName parameter can accept incoming strings, or it can accept incoming objects that have a ComputerName property. So, if you had a CSV file that had a ComputerName column, you could:
Again, assuming that CSV had a ComputerName column.
"Learn PowerShell Toolmaking in a Month of Lunches" (not to make you buy another training thing) really goes through this entire progression, also.
BUT... it's important when you post here to show an example of each step. Like, if I have no idea what the input looks like, it's tough for me to look at your code snippets and figure out what PowerShell is trying to do. Just a sample of "here's what the CSV file looks like," for example, and "here's what the first script is doing with it," can help a lot!
You're exactly right... I've been multitasking and skipped around... I see how I need to and will go through the full series from the beginning. I did see that book and after the videos may pick it up. I actually have your Windows Administrator's Automation Toolkit from MS Press :p
I assume I'm screwing things up with between object/string. Here's all the info and the error I get.
So, running Import-CSV against that file will produce two objects, each having a ComputerName property. That won't bind ByValue to a [string], but it can bind ByPropertyName:
But the parameter name (-ComputerName) and expected property name (ComputerName) HAVE TO BE SPELLED THE SAME for the magic to work. So it can't bind to -Csv, or -MyParam, or anything else.
And you do have to knock it off with Out-String. You're just upsetting the shell.
Would give you an array of two [string] objects in $Computers. But when you do this:
You're again missing some subtle things that the shell (v3 and later) does under the hood. You've given it a variable containing two [string] objects. It'll display them, but it'll control how it formats that display. You normally want to enumerate them.
So that you can work with each computer one at a time.
In short, your entire Import-PKCSV.ps1 is redundant. You could just do this:
And it'd work fine. Your Import-PKCSV.ps1 is just confusing things. There's no need for it. PowerShell already knows how to import CSVs without your help. You've just written a function that takes the usable, object-based output of Import-CSV and turns it into a difficult array of strings. Yuck.
Now, your error message is being generated by Get-Process. You didn't show me Get-Process in your code snippets, so I've no idea what you're doing with it.
Thanks! I appreciate your explanations! I had hopes to be able to pull from AD in the future and just use csv for now but I just simplified it. Here's my results that work.
well, the beauty of doing it right is that changing your input is easy.
But you've not really done it right :).
You've got a single script dealing with both input, work, and output. That's a poor design pattern. If you want to change this to work from AD, you actually have to change it. If you follow the right design pattern, it'll do everything.
If this is Invoke-WSUSUpdate.ps1...
Tools that perform a task shouldn't worry about getting their input – it should come via a parameter, which can accept pipeline input. When the tool doesn't care where the input comes from, the tool can accept input from many places. PowerShell can get computer names from many sources – why limit yourself to just one by hardcoding it into the tool?
My version an happily accept input from wherever I can get it. AD, a CSV, a text file, a database, whatever. I might have to write a tool (for example) to get computer names out of an SCCM database, but THAT tool can feed THIS one. Keeps everything flexible.
And with a -PassThru switch, THIS tool can be made to output the computer name it just operated against, perhaps feeding a second tool that produces a report or double-checks the operation.
Write tools that conform to PowerShell patterns and you end up working less.
I fumbled the ForEach within the Process which made me give up and add the input to the tool. Thanks for the complete script and the PassThru tip. Super cool! I'm on my way to making tools properly :p
Thanks again for your help and patience.
You must be logged in to reply to this topic.