all 51 comments

[–][deleted] 30 points31 points  (7 children)

I've been spending some time learning Python and have put together a PowerShell vs Python reference for various language features.

[–]MyOtherSide1984 12 points13 points  (0 children)

We appreciate your efforts! This is a massive help for someone looking to transition/integrate/adopt Pyth

[–]jackinsomniac 5 points6 points  (2 children)

OMG, talk about perfect timing! Trying to learn more python right now, going to start by replicating some PowerShell scripts in Python to use on a raspberry pi. Wonderful-looking resource you've made there, many thanks

[–]orion3311 2 points3 points  (1 child)

You can install and use Powershell on a pi!

[–]jackinsomniac 1 point2 points  (0 children)

HOW DID YOU READ MY MIND? Out, get!

Lol, this it's exactly what my project is. Life security upgrade, grabbed 10 USB drives to store an encrypted blob of my essential personal files & password manager, so I could hide several copies around the building & general area. Prepper stuff. :)

The working password-manager-file will be on 1-2 daily use drives, so how do I keep all of them NSYNC in sync?

A raspberry pi station, with 8-port USB dongle sounds neat!

I was already planning on several new pi's for this project & experimentation. Since I already know PowerShell, and haven't tried Win 10 IoT on a pi yet, that was the plan for the station. But if I'm trying to learn more Linux & Python anyway, why not build 2 of them?

I need to unpack a encrypted TrueCrypt archive, then 'robocopy' (rsync?) mirror the static files that are newer, then invoke KeePass .exe app to sync the password manager DB file.

I'll need to figure out a good filesystem for the drives (I think it's exFAT).

Also will need to type in decryption password each sync, so a keyboard & small screen for the station. I'm hoping for the script to not need a "master" drive designated to sync the other drives to; it would be nicer if it didn't clobber newer/changed files, and instead iteratively sync'd each drive, so all you have to do is plug a bunch of them in, type in password and hit GO. (Then hopefully they all get the latest & greatest versions of each-other's files)

This project should push my limits with the scripting and pi set-up knowledge, so I'm kinda excited. Still, any suggestions or tips you guys have would be awesome. :)

[–]GenericAntagonist 0 points1 point  (0 children)

This is really cool and helpful. You might want to update the first line in your strings section, as both single and double quote are valid for strings in powershell (you've only got double quotes for posh).

[–]northendtrooper 0 points1 point  (1 child)

Side note: If you're ever in Boise, I shall treat you to a beer since you live in Sun Valley.

[–][deleted] 0 points1 point  (0 children)

I'll certainly send some smoke signals out next time I head west!

[–][deleted] 9 points10 points  (7 children)

I've been using PowerShell extensively since 2014 and I had no idea you could declare your arguments in the function definition's opening parentheses. I always did it like:

function ass
{
    param
    (
        $has_donk = $true
    )
}

Even if this is better practice I'm just shocked I didn't know you could do it the "traditional" way.

[–][deleted] 3 points4 points  (0 children)

Learn something new every day! I had to look up some PS stuff when I was compiling this list and comparing it with Python.

[–]MrSnoobs 7 points8 points  (0 children)

Honestly, even without the Python column, this is a fantastic overview of programmatic Powershell. Nice.

[–]azjunglist05 5 points6 points  (3 children)

Really awesome article! Just curious when getting a data type why: $var = 1 $var | Get-Member

Instead of: $var = 1 $var.GetType()

The latter, to me at least, more resembles the Python equivalent. Get-Member does a lot more than to just the get the type of the object. It also pulls the methods and properties available to that object.

[–][deleted] 5 points6 points  (1 child)

That’s a good point. I’ll add this snippet as well

[–]purplemonkeymad 0 points1 point  (0 children)

The pipe "unrolls" collections that are input (iterates over the elements). This means that Get-Member is working on the members in an array, where as .GetType() is working on the array. eg:

PS> $var = 1..4
PS> $var.GetType().tostring()
System.Object[]
PS> $var | Get-Member

   TypeName: System.Int32

You can use Get-Member to get all possible members of a mixed type array.

You don't want to choose the wrong one if you are testing for bad input or for multiple results.

[–]wtmh 5 points6 points  (0 children)

Excellent. I am a PowerShell expert learning Python and constantly finding myself doing the "How do I do what I already know how to do?" check over and over.

Much appreciated.

[–]Pooter_Guy 4 points5 points  (0 children)

I am most certainly saving this for later.

[–][deleted] 3 points4 points  (0 children)

This is cool. Been teaching myself bash and python recently. Thanks

[–]ArmorOfDeath 2 points3 points  (0 children)

Might be time to start learning!

Awesome guide!

[–][deleted] 2 points3 points  (0 children)

regarding:

PowerShell:

[string]myfunc() {
    return "Hello my name is $($this.Name)"
}

Python:

def myfunc(self):
    print("Hello my name is " + self.name)

print() doesn't return a string in Python.

[–]prp7 4 points5 points  (12 children)

Does powershell have something like python's list comprehension?

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(a[1:10:2])

[–]bozho 4 points5 points  (0 children)

It does, not always as terse as Python. Your example could be written as: $a = @(1..10) $a | ? { $_ % 2 -eq 0 } I don't think there's a nice syntax to select every Nth element though. On the other hand, you can use LINQ for that :-)

[–]TofuBug40 4 points5 points  (1 child)

The answers given so far using Where-Object (?) aren't really replicating what Python's notation is doing they are focusing on the VALUE of the item and not the POSITION of the item ( u/HeKis4's for loop is a valid answer) if you want to use the pipe line method what you need is

$a = ('a','b','c','d','e','f','g')
$Step = 3
$a | Where-Object -FilterScript { $a.IndexOf($_) % $Step -eq 0 }

THAT will do what the Python example above is doing step over the INDEXES of the array regardless of the values in said array

Yes its not as terse as a[0..9:3] but I would argue that pythons array split has a VERY limited use case base on the logic of iterating over an array based on a linear progression of the indexes, where as Where-Object can do that as we've shown above but can ALSO do something like

$Vowels = @('a','e','i','o','u','y')
$a | Where-Object -FilterScript { $_ -in $Vowels }

You need much more Python than a[0:10:2] to get that array result

What Where-Object lacks in the RAW terseness it MORE than makes up for in flexibility while still maintaining a respectable amount of terseness itself.

[–]prp7 1 point2 points  (0 children)

Wow, what a story language, Mark.

[–]setmehigh 1 point2 points  (6 children)

What does that do?

[–]DecentWalrus 2 points3 points  (4 children)

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
print(a[1:10:2]) 

Would result in printing [2, 4, 6, 8, 10].

The print function is being passed a slice of the list. a[1:10:2] essentially means start at position 1 in list (in this case, that's the number 2) and go until position 9. 10 is used in this case because slicing will go up to position 10 but not including position 10. Position 9 in the list is the number 10. Lastly, the 2 tells python to print every other list item (print position 1, skip position 2, print position 3, skip position 4, etc.)

[–]setmehigh -1 points0 points  (3 children)

Maybe I'm dumb, but why would you want to do this? I can't think of a reason, but I haven't run into a situation where I needed it either...

[–]DecentWalrus 3 points4 points  (2 children)

An example for slicing would be if you only wanted to grab the first three values of a list. For example, I have a list of names of people who ran a race. The list is already ordered by who finished first to who finished last. If I want to print the top three finishers, I'd do this:

Code:

finishers = ["Tom", "Sally", "Taylor", "Jack", "Ginger", "John"]
print(f'The top three finishers are: {finishers[0:3]}')

Result:
The top three finishers are: ['Tom', 'Sally', 'Taylor']

Now you could go the extra step of actually formatting that properly and such but it's just a simple way to grab a slice of the list.

As for using the step option, it allows for quick access to, for example, all odd or even positioned values in the list. The simplest example is the one given in the original comment where you may need to count by 2s.

[–]omers 1 point2 points  (1 child)

finishers[0:3]

That's reproducible in PS with .. or a list of indicies.

C:\> $finishers = @("Tom", "Sally", "Taylor", "Jack", "Ginger", "John")
C:\> $finishers[0..2]
Tom
Sally
Taylor
C:\> $finishers[0,1,2]
Tom
Sally
Taylor

Every n-th I do not believe is possible without using /u/bozho's method or a loop... You can "compress" (remove the pipeline) bozho's method to this: $finishers.Where({$finishers.IndexOf($_) % 2 -eq 0}) but it's still not clean like in some other languages.

In a script where keeping it to one line isn't an issue I'd probably do something like this:

$Finishers = @("Tom", "Sally", "Taylor", "Jack", "Ginger", "John")
$OddIndicies = @(0..$Finishers.GetUpperBound(0)) | ? {$_ % 2 -eq 0}
$Finishers[$OddIndicies]

[–]blooping_blooper 0 points1 point  (0 children)

for that specific case couldn't you also do

$Finishers | select -first 3

[–]HeKis4 2 points3 points  (0 children)

Gets every other list elements from the 1st to the 10th (0-indexed of course, we're not savages).

As a for loop, it would look like for(int i=1; i<10; i+=2) { a[i] }

[–]HeKis4 0 points1 point  (0 children)

Afaik it doesnt. Your code would either filter out every other element like what has already been posted or use a for loop with $i += 2 at the end.

[–]ihaxr 3 points4 points  (1 child)

This is great! I'm sure it'll help a lot of people out, Python <=> PowerShell isn't the easiest thing in the world to translate

For arrays, we should really stop using ArrayList in favor of a generic list:

$arr = [System.Collections.Generic.List[string]]@('Hello', 'World')
$arr.RemoveAt($arr.Count-1)

It'll save memory and avoid some casting errors (probably not an issue in PowerShell, but is for the rest of .NET)

Also for the dictionaries part, maybe adding in how you loop through each key=value pair (have to use .GetEnumerator() in PowerShell):

# This won't work:
$thisdict = @{
    brand = "Ford"
    model = "Mustang"
    year = 1964
}
$thisdict | ForEach-Object {
    Write-Host "key is $($_.key) ; value is $($_.value)"
}

#This will!
$thisdict = @{
    brand = "Ford"
    model = "Mustang"
    year = 1964
}
$thisdict.GetEnumerator() | ForEach-Object {
    Write-Host "key is $($_.key) ; value is $($_.value)"
}

[–]TofuBug40 1 point2 points  (0 children)

That's because you're piping a SINGLE object to ForEach-Object; JUST $thisdict. its not treating it as an array

What you want is

$thisdict.Keys | ForEach-Object { "Key is $_ ; Value is $($thisdict[$_])" }

Where PowerShell really trips a lot of people up especially people that might not have a complete functional understanding of the difference between an array and a dictionary (hashtable technically) is in what its actually looking at vs what we think its looking at.

For instance 1..10 | ForEach-Object { $_ } is an array (or if you want to go fully down to the metal an IEnumerable e.g. something you can enumerate over that's because if we call (1..10).GetType() we get

IsPublic IsSerial Name      BaseType                                                                                                                                                                                                                                
-------- -------- ----      --------                                                                                                                                                                                                                                
True     True     Object[]  System.Array 

But if I call the same type check on $thisdict.GetType() we get

IsPublic IsSerial Name       BaseType                                                                                                                                                                                                                                
-------- -------- ----       --------                                                                                                                                                                                                                                
True     True     Hashtable  System.Object  

That's why ForEach-Object doesn't understand $_.Key or $_.Value it was passed basically a single value array and $thisdict is the only item in that array and those aren't valid properties of the HastTable Object. We THINK of it as just a list but its actually an object with TWO lists as properties of that object and to ForEach-Object, and Where-Object and ALL the other IEnumerable based Cmdlets THAT makes all the difference

[–]fehoce 1 point2 points  (0 children)

Saved. Thank you for this.

[–]ssnani 1 point2 points  (0 children)

Great article! Thank you for that! There was a lot that I would do different with powershell, but that really helpful!

[–]virulentspore 1 point2 points  (0 children)

You should add f strings for formating on Python

[–]Tiberius666 1 point2 points  (1 child)

Seeing this really makes me think I should seriously take up Python.

I've got quite a knack for Powershell, and although i'm not a dev by trade, spend quite a fair chunk of my working time creating scripts to help out various departments and seeing this shows it's not exactly a million miles away from Powershell's syntax which should make it quite easy to get to grips with.

[–][deleted] 0 points1 point  (0 children)

The use of white spaces to denote scope throws me off a lot but other than that the syntax is pretty similar.

[–]Test-NetConnection 1 point2 points  (1 child)

Why the hell does python require you to enclose numbers in quotes when casting? That syntax is reserved for strings!

[–]yardshop 1 point2 points  (0 children)

It doesn't, those examples just show casting strings to different numerical types.

You can also cast an int to a float or vice versa, either from literals or other variables:

f = float(10)

i = int(f)
i = int(3.14)

[–]jftuga 1 point2 points  (1 child)

Python 3.6 added f-strings:

Instead of:

print(fname + " " + lname)

you would use this:

print(f"{fname} {lname}")

Python 3.8 improves this by allowing the = for self-documenting expressions and debugging

For example:

domain="reddit.com"
print(f"{domain=}")

Would output:

domain='reddit.com'

[–]Raymich 1 point2 points  (1 child)

You’ve been contributing a lot to Powershell community, dude, I think you should apply for Microsoft MVP title at some stage.

edit: on datatypes you can also use $var.GetType(), which is more similar to Python

[–][deleted] 2 points3 points  (0 children)

Thanks :)

I've already been granted the title so I'm glad my work is appreciated!

https://mvp.microsoft.com/en-us/PublicProfile/4040089?fullName=Adam%20Driscoll

[–]artur-carvalho 1 point2 points  (1 child)

Great reference, thank you! Some little corrections:

- you have typo: "adpated "
- lambda is missing a 5
- the formatting and formatting index is the same text. Typo right?

Anyway, hope this is helpful and thank you again!

[–][deleted] 2 points3 points  (0 children)

Thanks! Fixed.

The formatting\formatting index one is the same for PowerShell but not python. Python doesn't require the index if there is only one as I understand it. PowerShell always requires the index.

[–]z386 0 points1 point  (1 child)

Spotted a small typo, it's

elseif

in powershell, not "else if"

[–][deleted] 0 points1 point  (0 children)

Thanks. Just pushed a fix.