Skip to content

New Practices for PowerShell Core #68

Description

@Jaykul

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

Activity

  1. rkeithhill commented on Aug 21, 2016

    @rkeithhill

    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

    👍

  2. Jaykul commented on Aug 21, 2016

    @Jaykul
    MemberAuthor

    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.

  3. dlwyatt commented on Aug 21, 2016

    @dlwyatt

    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.

  4. Jaykul commented on Aug 21, 2016

    @Jaykul
    MemberAuthor

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

  5. dlwyatt commented on Aug 21, 2016

    @dlwyatt

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

  6. Jaykul commented on Aug 21, 2016

    @Jaykul
    MemberAuthor

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

  7. dlwyatt commented on Aug 21, 2016

    @dlwyatt

    Oh? Where's that setting in the ISE?

  8. rkeithhill commented on Aug 21, 2016

    @rkeithhill

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

  9. Jaykul commented on Aug 21, 2016

    @Jaykul
    MemberAuthor

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

  10. rkeithhill commented on Aug 21, 2016

    @rkeithhill

    @Jaykul You only have two reasons for that? 😛

  11. dlwyatt commented on Aug 21, 2016

    @dlwyatt

    Don't get him started! :P

  12. rkeithhill commented on Aug 21, 2016

    @rkeithhill

    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.

  13. Jaykul commented on Aug 21, 2016

    @Jaykul
    MemberAuthor

    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

  14. 9 remaining items

  15. daviwil commented on Aug 22, 2016

    @daviwil

    +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.

  16. torgro commented on Aug 22, 2016

    @torgro

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

  17. mattmcnabb commented on Aug 22, 2016

    @mattmcnabb
    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.

  18. mattmcnabb commented on Aug 22, 2016

    @mattmcnabb
    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?

  19. torgro commented on Aug 22, 2016

    @torgro

    @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.

  20. daviwil commented on Aug 22, 2016

    @daviwil

    @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! :)

  21. stefanstranger commented on Aug 23, 2016

    @stefanstranger

    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?

  22. zloeber commented on Aug 24, 2016

    @zloeber

    Perhaps just in:
    Split-Path $Profile

  23. Jaykul commented on Aug 24, 2016

    @Jaykul
    MemberAuthor

    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 ...

  24. mattmcnabb commented on Aug 24, 2016

    @mattmcnabb
    Contributor

    @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!

  25. Jaykul commented on Aug 29, 2016

    @Jaykul
    MemberAuthor

    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

  26. Jaykul commented on Sep 1, 2016

    @Jaykul
    MemberAuthor

    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.

  27. lipkau commented on Jul 12, 2018

    @lipkau
  28. locked and limited conversation to collaborators on Jul 22, 2023
  29. converted this issue into a discussion #175 on Jul 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions