Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New Practices for PowerShell Core #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Jaykul opened this issue Aug 21, 2016 · 35 comments
Closed

New Practices for PowerShell Core #68

Jaykul opened this issue Aug 21, 2016 · 35 comments

Comments

@Jaykul
Copy link
Member

Jaykul commented Aug 21, 2016

There are going to be a few new things which we need to keep in mind to make our scripts work across multiple platforms. Windows, Nano, Linux, FreeBSD and OSX, ARM and IoT ...

Best Practices for Scripts and Modules:

  1. Don't put aliases into scripts. Aliases are (currently) different on each platform. Double-check using a tool like ResolveAlias.
  2. Add the shebang to scripts: #!/usr/bin/env pwsh (or the more fragile: #!/usr/bin/pwsh -noprofile)
  3. Save scripts with Unix style line endings, or the shebang will not work.
    Mac and Windows both accept \n but the Unix shell interpreter will choke on the carriage return in the shebang. If you don't add the shebang, this doesn't matter. Note that you can always fix it:
    Set-Content $scriptPath ((Get-Content $scriptPath -raw) -replace "\r") -Encoding utf8
  4. Always encode in utf-8.
  5. Be careful with paths. Use forward slashes. Use Join-Path and Split-Path
  6. ONLY use the new -PSEdition value allowed for #requires or module manifests, when you need to restrict to Core, not for Desktop, since it only works in PowerShell 5.1+
  7. ALWAYS use three digits for versions (i.e. 5.0.0, not 5.0) because they may be parsed as SemanticVersion which currently doesn't work unless you provide the patch version explicitly.
  8. [System.Environment]::CurrentDirectory doesn't in .Net Core. But if you need to call path-sensitive .Net APIs, you need to use [System.IO.Directory]::SetCurrentDirectory( (Get-Location -PSProvider FileSystem).ProviderPath ) to update the environment. Note that PowerShell sets the working directory fine when launching apps...

Finally: Test the code on Linux and Nano, if possible. There are differences.

ProTips

Use this in your profile: $PSDefaultParameterValues["Out-File:Encoding"] = "UTF8" to help with 1.

Don't forget you can install PowerShell 6 alphas side-by-side on Windows (they install to Program Files, and don't use the same profile or module paths). You don't have to set up docker or a VM to get started. It's just that in that scenario, you have access to things you won't have access to on Unix (like Set-ExecutionPolicy), so you should test elsewhere before publishing.

Cmdlet Differences

@rkeithhill
Copy link

rkeithhill commented Aug 21, 2016

Always encode in utf-8

BOM or no BOM? That's the question. :-) IIRC the .NET UTF8 encoder has BOM enabled by default and PS uses it that way.

Add the shebang to scripts: #!/usr/bin/powershell (or for mac: #!/usr/local/bin/powershell ... ??)

Surely Bash scripts must already have a way to handle the platform difference. Maybe you specify both and multiple #! are searched until the shell is found?

Instead of specifying \n, I would do something like:

$NL = [System.Environment]::NewLine

It would be nice if this were added as an automatic variable.

ALWAYS use three digits for versions

👍

@Jaykul
Copy link
Member Author

Jaykul commented Aug 21, 2016

OK, changed it to the best thing, which is #!/usr/bin/env powershell ... which would use the first powershell on the path.

But FreeBSD is a pain (and thus, OS X) and /usr/local/bin is not necessarily on the path.

Also, you can't specify parameters to PowerShell if you do that, like: #!/usr/bin/powershell -noprofile works, but #!/usr/bin/env powershell -noprofile doesn't, because the interpreters will try to look up "powershell -noprofile" so a ProTip is going to be to figure out a way to tell (in your profile) if PowerShell is being used as an interpreter vs. as a shell.

I will reword the bit about \n -- the point is that you must save your actual PowerShell script with JUST newlines, or shebangs do not work.

@dlwyatt
Copy link

dlwyatt commented Aug 21, 2016

That's a pain in the ass. Git will convert line endings for you, but not sure what happens if we're publishing to the Gallery from a Windows machine.

@Jaykul
Copy link
Member Author

Jaykul commented Aug 21, 2016

Just ... stop using carriage returns. It's 2016. 🎱 says YAGNI

@dlwyatt
Copy link

dlwyatt commented Aug 21, 2016

It's not like we're manually typing \r\n after every line. The editors do it. :P

@Jaykul
Copy link
Member Author

Jaykul commented Aug 21, 2016

Other than notepad.exe, it's always a setting.

@dlwyatt
Copy link

dlwyatt commented Aug 21, 2016

Oh? Where's that setting in the ISE?

@rkeithhill
Copy link

rkeithhill commented Aug 21, 2016

Are you sure Visual Studio allows you to configure line endings? You can configure it to warn you of inconsistent line endings.

@Jaykul
Copy link
Member Author

Jaykul commented Aug 21, 2016

OMG. I just remembered the other reason I despise ISE.

@rkeithhill
Copy link

@Jaykul You only have two reasons for that? 😛

@dlwyatt
Copy link

dlwyatt commented Aug 21, 2016

Don't get him started! :P

@rkeithhill
Copy link

I will reword the bit about \n -- the point is that you must save your actual PowerShell script with JUST newlines, or shebangs do not work.

I think it is worth differentiating this point between how you save your scripts and what you use in your scripts for NL.

@Jaykul
Copy link
Member Author

Jaykul commented Aug 21, 2016

I guess if you're using PowerShell on other OS's, you're going to outgrow ISE and start using VS Code anyway.

Also, if don't need the shebang functionality (i.e. running PowerShell scripts "as apps" or from bash), don't worry about it -- they work fine in PowerShell regardless.

@rkeithhill I had simply forgotten that particular reason. Anyway. Visual Studio just uses what's in the file already for encoding and for line endings, you just have to hit the File -> Advanced Save Options to set it, and it figures it out from the file from then on...

advancedsaveoptions

@dlwyatt
Copy link

dlwyatt commented Aug 21, 2016

There's quite a difference between authoring scripts that are compatible with other platforms and using them on Linux / Mac myself. I don't need to "outgrow" my preferred editor, thank you very much.

I suspect that either David or Tobias will add that option now that we've realized it's a problem.

@Jaykul
Copy link
Member Author

Jaykul commented Aug 21, 2016

Or, you know ... perl -i -pe's/\r$//;' .\yourscript.ps1

Or powershell '&{param($f)sc $f ((gc $f -raw)-replace''\r'') -Enc utf8}' .\yourscript.ps1

If you set the encoding at the same time, you could use a file watcher and .... sigh

@kilasuit
Copy link

I may move to VSCode for xplat use but for me ISE currently does exactly what I want it to. Though I am with @dlwyatt and hope that @daviwil will get chance to add this to ISE and preferably the ISE-Preview as that should be much easier to ship updates to.

@mattmcnabb
Copy link
Contributor

In case anyone is reading this and needs to know - the line endings setting in VSCode is \r\n by default. Look for the settings files.eol and change it to \n. Found this today after I discovered my .gitignore file wasn't working because of Windows-style line endings.

@mattmcnabb
Copy link
Contributor

@kilasuit I agree with you about ISE. I'm so used to the debugging experience there that it will be hard to switch fully to VSCode, although I now prefer it as my go-to general purpose editor. For me the debugging is just a bit slow and clunky-feeling for PowerShell. I'm hoping that changes as VSCode matures - maybe we'll get an all-in-one terminal and debugger? Or maybe I'll just get used to the one in VSCode and won't have to worry about multiple editors anymore? I think only @daviwil knows the answer to this right now ;-P

@rkeithhill
Copy link

@mattmcnabb Keep in mind that with the PowerShellEditorServices, where the debugger lives, we're only at version 0.7.0. It will get better, then worse for a bit, then better. :-) Hopefully by 1.0.0 it will meet most folks expectations.

Also, last I checked, setting function, conditional and action breakpoints is not something ISE natively supports in the UI nor is there debug UI for inspecting variables and bouncing around the call stack. Hopefully, we'll soon have the ability to set variable values from the debug UI in VSCode.

@mattmcnabb
Copy link
Contributor

mattmcnabb commented Aug 22, 2016

@rkeithhill I fully understand where you're at with the PowerShell extension, and don't get me wrong - I really dig it. I've been using VSCode for a while now to to markdown and some other general editing, so doing PowerShell in it is very attractive. Cross-platform makes this even more attractive. Although I'm more used to the ISE, it also hasn't really developed much since v3.0 so I'm really looking forward to how VSCode and the PowerShell extension progress.

You're right about the ISE not supporting the more advanced debugging like conditional breakpoints - I still use Set-PSBreakpoint for those scenarios. The immediacy that I get with the ISE is due to the debugging session taking place in the active console. It feels very natural to me since this is where I learned debugging in the first place. I've also been using ISESteroids for a while now, and this has made the ISE a pretty powerfull editor. There's a place in my heart for the ISE, but I believe that VSCode is probably the editor of the future.

EDIT: Kudos to you and @daviwil for all your great work with the editor stuff in the last year or so, and for your constant community engagement!

@daviwil
Copy link

daviwil commented Aug 22, 2016

@mattmcnabb I'd definitely like to hear more about what's clunky in the debugging experience in VS Code. If you get a chance, wanna start a discussion over at the vscode-powershell repo so we can talk about how to make it better?

Regarding the console experience in VS Code, I definitely want to start leveraging the new Integrated Terminal for the editing experience. Now that the PS on Linux launch is over I'll have some time to devote to figuring this out. I'm also pretty well connected now with the guy who works on that feature in VS Code so hopefully he and I can work together to get the ideal experience together.

Regarding the initial purpose of this issue, I agree completely with the ideas and intent of Jaykul's new best practices. Ship it!

@KevinMarquette
Copy link

KevinMarquette commented Aug 22, 2016

I know we have general Powershell best practices and they are there for a reason, but we should put renewed emphasis on some of them.

  • Don't use aliases in scripts/modules
  • Use Join-Path and Split-Path when manipulating file and directory paths.

@daviwil
Copy link

daviwil commented Aug 22, 2016

+1 on Join-Path and Split-Path. I think using / on all platforms should work fine, but those might help for dealing with path quoting, etc.

@torgro
Copy link

torgro commented Aug 22, 2016

Maybe we should just create some default Pester tests that users could run on their code to verify compliance with the new "stylesheet"?

@mattmcnabb
Copy link
Contributor

@torgro I think PSScriptAnalyzer rules would be a better fit for this. Depending on your editor you can get live feedback on best practices while you're writing scripts.

@mattmcnabb
Copy link
Contributor

@daviwil I'd be glad to open the discussion on this, although I've done little real debugging in VSCode. I tend to do this in the ISE and am ready to accept that the issues are probably my own. I'll dig in and try to work up something a bit more coherent and post it as an issue if it feels necessary. Maybe that will help inform your direction on further integration with the live terminal?

@torgro
Copy link

torgro commented Aug 22, 2016

@mattmcnabb I forgot about PSScriptAnalyzer. I think both would be sweet. Reason for that is many people use a regular texteditor like notepad++/notepad/etc. At least that is my impression from forums. Very, very few people use PSSA and/or Pester.

I do most of my work in VSCode (thank you @daviwil if I have not said that before) and use Pester quite a bit. In any project that target cross-platform compatibility, it makes sense to have tests that verify these best practices.

@daviwil
Copy link

daviwil commented Aug 22, 2016

@mattmcnabb yeah, if you can give me an overview of your typical debugging workflow in the ISE that'd help me figure out how to replicate it in VS Code with the integrated terminal. Probably how you use the ISE isn't far off from what others do, so it'd be good to have the general debugging workflow patterns written down somewhere.

And thanks Tore! :)

@stefanstranger
Copy link

What would be the best location for storing user configurations (like API clientid and secret) for PowerShell modules? For Windows I used c:\users\stefstr etc.a and user environment variables. For usage on Linux that's not going to work. Any suggestions?

@zloeber
Copy link

zloeber commented Aug 24, 2016

Perhaps just in:
Split-Path $Profile

@Jaykul
Copy link
Member Author

Jaykul commented Aug 24, 2016

Yeah, normally per-user config stuff would be ~/.config/powershell ... but it's going to be confusing if something in there gets added to PSModulePath too ...

@mattmcnabb
Copy link
Contributor

mattmcnabb commented Aug 24, 2016

@daviwil I posted a description of my issues here. I got issue # 256! What's the $MaximumIssueCount on the project? It might start dropping the old ones off...

Anyway, I hope this doesn't sound like too much of a rant!

@Jaykul
Copy link
Member Author

Jaykul commented Aug 29, 2016

Ok, found another one ... we're going to need a list of cmdlets which are implemented drastically differently. Invoke-WebRequest, for instance, has lost it's error handling

@Jaykul
Copy link
Member Author

Jaykul commented Sep 1, 2016

And another: [System.Environment]::CurrentDirectory doesn't exist, so if you need to call path-sensitive .Net APIs, you need to use [System.IO.Directory]::SetCurrentDirectory( $pwd ) instead to set the .net environment.

@lipkau
Copy link

lipkau commented Jul 12, 2018

@PoshCode PoshCode locked and limited conversation to collaborators Jul 22, 2023
@Jaykul Jaykul converted this issue into discussion #175 Jul 22, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
None yet
Development

No branches or pull requests